Advanced coordinate conversion#

This tutorial delves deeper into conversions between geographic coordinates and HEALPix indices, exploring the different indexing schemes.

HEALPix indexing schemes#

HEALPix supports three different indexing schemes:

  • nested

  • ring

  • zuniq

Conversions from geographic coordinates index#

Nested and Ring#

import numpy as np
from healpix_geo.nested import lonlat_to_healpix as nested_lonlat
from healpix_geo.ring import lonlat_to_healpix as ring_lonlat

# Same point, two schemes
lon, lat = np.array([0.0]), np.array([45.0])
depth = 8

ipix_nested = nested_lonlat(lon, lat, depth, "WGS84")
ipix_ring = ring_lonlat(lon, lat, depth, "WGS84")

print(f"Point (0°, 45°) at depth={depth}:")
print(f"  Nested: {ipix_nested[0]}")
print(f"  Ring:   {ipix_ring[0]}")
Point (0°, 45°) at depth=8:
  Nested: 43775
  Ring:   115680

Warning

The nested and ring indices are not interchangeable. The same point has different indices depending on the scheme!

Nested and Zuniq#

from healpix_geo.zuniq import from_nested, to_nested
import numpy as np

# Nested → Zuniq
ipix_nested = 349440
depth = 8
zuniq_id = from_nested(ipix_nested, depth)

print(f"Nested (depth={depth}, ipix={ipix_nested}) → Zuniq: {zuniq_id}")

# Zuniq → Nested
ipix_back, depth_back = to_nested(zuniq_id)
print(f"Zuniq {zuniq_id} → Nested (depth={depth_back}, ipix={ipix_back})")
Nested (depth=8, ipix=349440) → Zuniq: [3073711143726874624]
Zuniq [3073711143726874624] → Nested (depth=[8], ipix=[349440])

Visual comparison#

Let see how the different schemes are organising cells :

Hide code cell source

import matplotlib.pyplot as plt
from healpix_geo.nested import vertices as nested_vertices
from healpix_geo.ring import vertices as ring_vertices

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 6))

depth = 2
n_cells = 12 * 4**depth

# Sample cells
sample_cells = range(0, n_cells, max(1, n_cells // 50))

# Nested
for ipix in sample_cells:
    lons, lats = nested_vertices(np.array([ipix]), depth, "WGS84")
    lons_closed = np.append(lons[:, 0], lons[0, 0])
    lats_closed = np.append(lats[:, 0], lats[0, 0])

    ax1.plot(lons_closed, lats_closed, "b-", linewidth=0.5, alpha=0.5)
    ax1.text(
        lons[:, 0].mean(),
        lats[:, 0].mean(),
        str(ipix),
        ha="center",
        va="center",
        fontsize=6,
    )

ax1.set_title(f"Nested Scheme (depth={depth})", fontsize=14)
ax1.set_xlabel("Longitude (°)")
ax1.set_ylabel("Latitude (°)")
ax1.grid(True, alpha=0.3)

# Ring
for ipix in sample_cells:
    lons, lats = ring_vertices(np.array([ipix]), depth, "WGS84")
    lons_closed = np.append(lons[:, 0], lons[0, 0])
    lats_closed = np.append(lats[:, 0], lats[0, 0])

    ax2.plot(lons_closed, lats_closed, "r-", linewidth=0.5, alpha=0.5)
    ax2.text(
        lons[:, 0].mean(),
        lats[:, 0].mean(),
        str(ipix),
        ha="center",
        va="center",
        fontsize=6,
    )

ax2.set_title(f"Ring Scheme (depth={depth})", fontsize=14)
ax2.set_xlabel("Longitude (°)")
ax2.set_ylabel("Latitude (°)")
ax2.grid(True, alpha=0.3)

plt.tight_layout()
plt.show()
../_images/0eac67722e12255aa1c8c76386f466584f2d9a3286189cc605b515b32fbb6768.png

Choice Table#

Need

Recommended Scheme

General Application

nested

Hierarchical Navigation

nested

Spherical harmonics

ring

MOC

zuniq

Order by latitude

ring

Next Steps#

Cover Requests
Cover requests
Working MOC
Work with MOC