"""
Utility functions for plotting.
"""
from .constants import EARTH_RADIUS, MOON_RADIUS
from .utils import find_file, Time
import numpy as np
from PIL import Image as PILImage
import ipyvolume as ipv
[docs]def load_earth_file():
"""
Loads and resizes an image of the Earth.
This function locates a file named "earth.png" using the `find_file` function,
opens it as an image using the `PILImage.open` method, and resizes it to
1/5th of its original dimensions (5400x2700 scaled down to 1080x540).
The resized image is then returned.
Returns:
PIL.Image.Image: The resized Earth image.
"""
earth = PILImage.open(find_file("earth", ext=".png"))
earth = earth.resize((5400 // 5, 2700 // 5))
return earth
[docs]def draw_earth(time, ngrid=100, R=EARTH_RADIUS, rfactor=1):
"""
Parameters
----------
time : array_like or astropy.time.Time (n,)
If float (array), then should correspond to GPS seconds;
i.e., seconds since 1980-01-06 00:00:00 UTC
ngrid: int
Number of grid points in Earth model.
R: float
Earth radius in meters. Default is WGS84 value.
rfactor: float
Factor by which to enlarge Earth (for visualization purposes)
"""
earth = load_earth_file()
from numbers import Real
from erfa import gst94
lat = np.linspace(-np.pi / 2, np.pi / 2, ngrid)
lon = np.linspace(-np.pi, np.pi, ngrid)
lat, lon = np.meshgrid(lat, lon)
x = np.cos(lat) * np.cos(lon)
y = np.cos(lat) * np.sin(lon)
z = np.sin(lat)
u = np.linspace(0, 1, ngrid)
v, u = np.meshgrid(u, u)
# Need earth rotation angle for times
# Just use erfa.gst94.
# This ignores precession/nutation, ut1-tt and polar motion, but should
# be good enough for visualization.
if isinstance(time, Time):
time = time.gps
if isinstance(time, Real):
time = np.array([time])
mjd_tt = 44244.0 + (time + 51.184) / 86400
gst = gst94(2400000.5, mjd_tt)
u = u - (gst / (2 * np.pi))[:, None, None]
v = np.broadcast_to(v, u.shape)
return ipv.plot_mesh(
x * R * rfactor, y * R * rfactor, z * R * rfactor,
u=u, v=v,
wireframe=False,
texture=earth
)
[docs]def load_moon_file():
"""
Loads and resizes an image of the Moon.
This function locates a file named "moon.png" using the `find_file` function,
opens it as an image using the `PILImage.open` method, and resizes it to
1/5th of its original dimensions (5400x2700 scaled down to 1080x540).
The resized image is then returned.
Returns:
PIL.Image.Image: The resized Moon image.
"""
moon = PILImage.open(find_file("moon", ext=".png"))
moon = moon.resize((5400 // 5, 2700 // 5))
return moon
[docs]def draw_moon(time, ngrid=100, R=MOON_RADIUS, rfactor=1):
"""
Parameters
----------
time : array_like or astropy.time.Time (n,)
If float (array), then should correspond to GPS seconds;
i.e., seconds since 1980-01-06 00:00:00 UTC
ngrid: int
Number of grid points in Earth model.
R: float
Earth radius in meters. Default is WGS84 value.
rfactor: float
Factor by which to enlarge Earth (for visualization purposes)
"""
moon = load_moon_file()
from numbers import Real
from erfa import gst94
lat = np.linspace(-np.pi / 2, np.pi / 2, ngrid)
lon = np.linspace(-np.pi, np.pi, ngrid)
lat, lon = np.meshgrid(lat, lon)
x = np.cos(lat) * np.cos(lon)
y = np.cos(lat) * np.sin(lon)
z = np.sin(lat)
u = np.linspace(0, 1, ngrid)
v, u = np.meshgrid(u, u)
# Need earth rotation angle for t
# Just use erfa.gst94.
# This ignores precession/nutation, ut1-tt and polar motion, but should
# be good enough for visualization.
if isinstance(time, Time):
time = time.gps
if isinstance(time, Real):
time = np.array([time])
mjd_tt = 44244.0 + (time + 51.184) / 86400
gst = gst94(2400000.5, mjd_tt)
u = u - (gst / (2 * np.pi))[:, None, None]
v = np.broadcast_to(v, u.shape)
return ipv.plot_mesh(
x * R * rfactor, y * R * rfactor, z * R * rfactor,
u=u, v=v,
wireframe=False,
texture=moon
)