Search code examples
pythonmatplotlibplothealpyprojscatter

How to make a figure with scatter plots on the sky as subplots?


I am trying to make a figure with 4 subplots (in 2 columns and 2 rows). Each of them should contain a healpy projscatter subplot or a scatter plot on the sky of another kind. But I see no easy way provided by healpy to do this. Can someone provide a useful code? thx


Solution

  • This is an example code that will work without healpy, instead using exclusively matplotlib:

    import matplotlib.pyplot as plt
    import numpy as np
    import healpy as hp
    
    # Function to create a healpy projscatter plot
    def create_projscatter_plot(ax):
        ax.scatter(x=np.radians([0, 45, 90, 150]), y=np.radians([40, 55, 120, 170]), alpha=0.5, s=10)
        ax.grid()
        # Set custom ticks for declination
        # ax.set_xticks([])
    
    
    # Create a 2x2 subplot grid
    fig, axs = plt.subplots(2, 2, figsize=(10, 7), subplot_kw={'projection': 'mollweide'})
    
    # Create projscatter plots for each subplot
    create_projscatter_plot(axs[0, 0])
    create_projscatter_plot(axs[0, 1])
    create_projscatter_plot(axs[1, 0])
    create_projscatter_plot(axs[1, 1])
    
    # Add titles and adjust layout
    axs[0, 0].set_title('Subplot 1')
    axs[0, 1].set_title('Subplot 2')
    axs[1, 0].set_title('Subplot 3')
    axs[1, 1].set_title('Subplot 4')
    
    plt.tight_layout()
    plt.show()
    

    enter image description here

    There is also the option to use hp.projscatter itself, but it has been reported before here and here, that using it in subplots causes data points to be copied from a subplot to another subplot, e.g. the following code

    import healpy as hp
    import numpy as np
    import matplotlib.pyplot as plt
    
    fig, axs = plt.subplots(2, 2, figsize=(10, 6))
    
    plt.axes(axs[0,0])
    hp.mollview(hold=True)
    hp.projscatter([0], [30], lonlat=True, coord='G')
    hp.graticule()
    
    plt.axes(axs[0,1])
    hp.mollview(hold=True)
    hp.projscatter([0], [-30], lonlat=True, coord='G')
    hp.graticule()
    
    plt.axes(axs[1,0])
    hp.mollview(hold=True)
    hp.projscatter([0], [45], lonlat=True, coord='G')
    hp.graticule()
    
    plt.axes(axs[1,1])
    hp.mollview(hold=True)
    hp.projscatter([0], [-45], lonlat=True, coord='G')
    hp.graticule()
    

    should plot in each subplot just one data point, instead it creates below's mess. So far no solution has been found for this erratic behaviour and it might be best to use matplotlib instead of hp.projscatter for making multiple scatter-subplots of the sky:

    enter image description here

    Eventually, I also asked one of the main contributors to healpy, he answered on github and following his advice by using newprojview I created these great subplots with the scatter-subplots showing nominal behaviour:

    m = np.zeros(hp.nside2npix(32))
    m2= np.random.random(hp.nside2npix(32))
    
    projview(
        m,
        # cmap="planck",
        graticule=True,
        graticule_labels=True,
        sub=221,
        override_plot_properties={"figure_width": 13, "figure_size_ratio": 0.53},
        cbar=None,
    );
    plt.scatter(np.deg2rad([0, -30, 30]), np.deg2rad([0,0,0]), color="red", s=80);
    
    projview(
        m,
        # cmap="planck",
        graticule=True,
        graticule_labels=True,
        cbar=None,
        sub=222,
    );
    plt.tight_layout();
    plt.scatter(np.deg2rad([90, 90, 90]), np.deg2rad([45,-45,0]), color="black", s=80);
    
    projview(
        m2,
        cmap="planck",
        sub=223,
    );
    plt.scatter(np.deg2rad([0, -30, 30]), np.deg2rad([30,30,30]), color="green", s=80);
    
    projview(
        m2,
        cmap="planck",
        sub=224,
    );
    plt.tight_layout();
    plt.scatter(np.deg2rad([-30, -30, -30]), np.deg2rad([45,-45,0]), color="white", s=80);
    

    enter image description here