Diana Jovmir
Diana Jovmir

Reputation: 41

Healpy plotting: How do i make a figure with subplots using the healpy.mollview projection?

I've just recently started trying to use healpy and i can't figure out how to make subplots to contain my maps. I have a thermal emission map of a planet as function of time and i need to look at it at several moments in time (lets say 9 different times) and superimpose some coordinates, to check that my planet is rotating the right way.

So far, i can do 2 things.

  1. Make 9 different figures with the superimposed coordinates.
  2. Make a figure with 9 subplots containing 9 different maps but that superimposes all of my coordinates on all of my subplots, instead of just the time-appropriate ones.

I'm not sure if this is a very simple problem but it's been driving me crazy and i cant find anything that works.

I'll show you what i mean:

OPTION 1:

import healpy as hp 
import matplolib.pyplot as plt 





MAX = 10**(23)
MIN = 10**10

for i in range(9):
    t = 4000+10*i

    hp.visufunc.mollview(Fmap_wvpix[t,:],
                         title = "Map at t="+str(t), min = MIN, max=MAX))

    hp.visufunc.projplot(d[t,np.where(np.abs(d[t,:,2]-SSP[t])<0.5),1 ],
                         d[t,np.where(np.abs(d[t,:,2]-SSP[t])<0.5),2], 
                         'k*',markersize = 6)

    hp.visufunc.projplot(d[t,np.where(np.abs(d[t,:,2]-(SOP[t]))<0.2),1 ],
                         d[t,np.where(np.abs(d[t,:,2]-(SOP[t]))<0.2),2], 
                         'r*',markersize = 6)

This makes 9 figures that look pretty much like this :

Flux map superimposed with some stars at time = t

But i need a lot of them so i want to make an image that contains 9 subplots that look like the image.

OPTION 2:

fig = plt.figure(figsize = (10,8)) 

for i in range(9):
    t = 4000+10*i

    hp.visufunc.mollview(Fmap_wvpix[t,:],
                         title = "Map at t="+str(t), min = MIN, max=MAX,
                         sub = int('33'+str(i+1)))


    hp.visufunc.projplot(d[t,np.where(np.abs(d[t,:,2]-SSP[t])<0.5),1 ],
                         d[t,np.where(np.abs(d[t,:,2]-SSP[t])<0.5),2], 
                         'k*',markersize = 6)

    hp.visufunc.projplot(d[t,np.where(np.abs(d[t,:,2]-(SOP[t]))<0.2),1 ],
                         d[t,np.where(np.abs(d[t,:,2]-(SOP[t]))<0.2),2], 
                         'r*',markersize = 6)

This gives me subplots but it draws all the projplot stars on all of my subplots! (see following image)

Subplots with too many stars

I know that i need a way to call the axes that has the time = t map and draw the stars for time = t on the appropriate map, but everything i've tried so far has failed. I've mostly tried to use projaxes thinking i can define a matplotlib axes and draw the stars on it but it doesnt work. Any advice?

Also, i would like to draw some lines on my map as well but i cant figure out how to do that either. The documentation says projplot but it won't draw anyting if i don't tell it i want a marker.

PS: This code is probably useless to you as it won't work if you don't have my arrays. Here's a simpler version that should run:

import numpy as np
import healpy as hp
import matplotlib.pyplot as plt


NSIDE = 8
m = np.arange(hp.nside2npix(NSIDE))*1


MAX = 900
MIN = 0


fig = plt.figure(figsize = (10,8)) 
for i in range(9):
    t = 4000+10*i

    hp.visufunc.mollview(m+100*i, title = "Map at t="+str(t), min = MIN, max=MAX, 
                         sub = int('33'+str(i+1)))

    hp.visufunc.projplot(1.5,0+30*i, 'k*',markersize = 16)

So this is supposed to give me one star for each frame and the star is supposed to be moving. But instead it's drawing all the stars on all the frames.

What can i do? I don't understand the documentation.

Upvotes: 4

Views: 5415

Answers (3)

NeStack
NeStack

Reputation: 2012

I was looking for an answer to the same question, but when using the suggestion by Daniel Lenz the two subplots ended up having different sizes. The solution for me was to use gridspec_kw={'height_ratios': [1, 1]} like in the code below:

import matplotlib.pyplot as plt
import numpy as np
import healpy as hp

nside = 2**6
npix = hp.nside2npix(nside)

# Create a figure with two subplots
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 8), gridspec_kw={'height_ratios': [1, 1]})

plt.axes(ax1)
hp.mollview(np.random.random(hp.nside2npix(32)), min=0, max=10, hold=True)

plt.axes(ax2)
hp.mollview(np.random.random(hp.nside2npix(32)), min=0, max=10, hold=True)

# Adjust layout
plt.tight_layout()

# Show the plot
plt.show()

enter image description here

If you want to have just one colorbar disable in both subplots the colorbar with hp.mollview(..., cbar=False) and add a colorbar to the figure as a whole with

cbar_ax = fig.add_axes([0.2, 0.05, 0.6, 0.02])  # Adjust the values as needed
cbar = fig.colorbar(img2, cax=cbar_ax, orientation='horizontal', ticks=[0, 1, 10])
cbar_ax.set_xlim(0, 10)

Some time after the question has been asked there has been a newer addition to the healpy package called newprojview, that produces subplots like these:

m= np.random.random(hp.nside2npix(32))

projview(
    m,
    cmap="planck",
    sub=221,
    override_plot_properties={"figure_width": 13, "figure_size_ratio": 0.53},
);
plt.scatter(np.deg2rad([0, -30, 30]), np.deg2rad([0,0,0]), color="blue", s=80);

projview(
    m,
    cmap="planck",
    sub=222,
);
plt.tight_layout();
plt.scatter(np.deg2rad([90, 90, 90]), np.deg2rad([45,-45,0]), color="black", s=80);

projview(
    m,
    cmap="planck",
    sub=223,
);
plt.scatter(np.deg2rad([0, -30, 30]), np.deg2rad([30,30,30]), color="green", s=80);

projview(
    m,
    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

Upvotes: 0

Daniel Lenz
Daniel Lenz

Reputation: 3867

If you want to have healpy plots in matplotlib subplots, the following would be the way to go. The key is to use plt.axes() to select the active subplot and to use the hold=True keyword in the healpy functions.

import healpy as hp
import numpy as np
import matplotlib.pyplot as plt

fig, (ax1, ax2) = plt.subplots(ncols=2)

plt.axes(ax1)
hp.mollview(np.random.random(hp.nside2npix(32)), hold=True)

plt.axes(ax2)
hp.mollview(np.arange(hp.nside2npix(32)), hold=True)

enter image description here

Upvotes: 7

DarkMatter42
DarkMatter42

Reputation: 31

I have just encountered this question looking for a solution to the same problem, but managed to find it from the documentation of mollview (here).

As you notice there, they say that 'sub' received the same syntax as the function subplot (from matplotlib). This format is:

( # of rows, # of columns, # of current subplot)

E.g. to make your plot, the value sub wants to receive in each iteration is

sub=(3,3,i) 

Where i runs from 1 to 9 (3*3).

This worked for me, I haven't tried this with your code, but should work.

Hope this helps!

Upvotes: 3

Related Questions