Source code for rms.spot
# Licensed under the MIT License - see LICENSE
import numpy as np
import astropy.units as u
import matplotlib.pyplot as plt
from astropy.coordinates import Angle
__all__ = ['Spot']
[docs]class Spot(object):
"""
Starspot object.
"""
@u.quantity_input(latitude=u.deg, longitude=u.deg)
def __init__(self, latitude, longitude, radius):
"""
Parameters
----------
latitude : `~astropy.units.Quantity`
Spot latitude
longitude : `~astropy.units.Quantity`
Spot longitude
radius : float
Spot radius in units of stellar radii
"""
self.latitude = latitude
self.longitude = longitude
self.radius = radius
[docs] @classmethod
def at_random_position(cls, radius):
lat, lon = generate_random_coord()
return cls(lat, lon, radius)
@property
def r(self):
"""Spot radius (alias)"""
return self.radius
@property
def theta(self):
"""Spot ``theta`` [radians] where ``theta = 90 deg - latitude``"""
return np.pi/2 - self.latitude.to(u.rad).value
@property
def phi(self):
"""Spot ``phi`` [radians] where ``phi = longitude``"""
return self.longitude.to(u.rad).value
def __repr__(self):
return "<Spot: lat={0}, lon={1}, rad={2}>".format(self.latitude,
self.longitude,
self.radius)
[docs] def plot(self, ax=None, projection='hammer',
plot_kwargs=dict(marker=',', color='k')):
"""
Make a simple plot of this spot.
Parameters
----------
ax : `~matplotlib.pyplot.Axes`
Axis object
plot_kwargs : dict
Keyword arguments to pass to `~matplotlib.pyplot.plot`
Returns
-------
ax : `~matplotlib.pyplot.Axes`
Updated axis object
"""
if ax is None:
fig = plt.figure()
ax = fig.add_subplot(111, projection=projection)
phi = Angle(self.longitude).wrap_at(np.pi*u.rad)
theta = (np.pi/2 * u.rad - self.latitude)
lat, lon = rtp_to_edge(self.radius, phi, theta)
ax.plot(lon, lat, **plot_kwargs)
ax.grid()
return ax
@u.quantity_input(theta=u.rad, phi=u.rad)
def rtp_to_edge(radius, theta, phi, n_points=1000):
"""
Use the haversine formula to compute the boundary lat/lon coordinates for a
circular spot centered on ``(theta, phi)``, with radius ``radius` in units
of the stellar radius.
Parameters
----------
radius : float
Spot radius [R_star]
theta : `~astropy.units.Quantity`
Spot theta coord (90 deg - latitude)
phi : `~astropy.units.Quantity`
Spot phi coord (longitude)
n_points : int
Number of points to include in the circle boundary
Returns
-------
lat : `~astropy.units.Quantity`
Latitudes of spot boundary
lon : `~astropy.units.Quantity`
Longitudes of spot boundary
"""
lat1 = np.pi/2 - theta.to(u.rad).value
lon1 = phi.to(u.rad).value
d = radius
thetas = np.linspace(0, -2*np.pi, n_points)[:, np.newaxis]
lat = np.arcsin(np.sin(lat1) * np.cos(d) + np.cos(lat1) *
np.sin(d) * np.cos(thetas))
dlon = np.arctan2(np.sin(thetas) * np.sin(d) * np.cos(lat1),
np.cos(d) - np.sin(lat1) * np.sin(lat))
lon = ((lon1 - dlon + np.pi) % (2*np.pi)) - np.pi
return lat*u.rad, lon*u.rad
def generate_random_coord(n=1):
"""
Generate random latitude/longitude pairs, of length ``n``.
"""
random_longitude = 2*np.pi*np.random.rand(n)
random_z = 2*np.random.rand(n) - 1
random_latitude = np.arcsin(random_z)
result = np.vstack([random_latitude, random_longitude]).T * u.rad
if result.shape[0] == 1:
return result[0]
return result