"""
Most of the functions assumes the :mod:`irfpy.vexpvat.vexspice` module is initialized prior.
>>> from irfpy.vexpvat import vexspice as vs
>>> vs.init()
"""
import datetime
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mplpatches
from irfpy.vexpvat import vexspice as vs
from irfpy.util.intersection import isvisible
from irfpy.util import utc
from irfpy.util.nptools import unjump_periodic
from irfpy.venus import rv, icb, bowshock
[docs]class Panel_xr_orbit:
""" Create a matplotlib axis.
*Usage*
1. Import needed modules
::
import datetime
import matplotlib.pyplot as plt
from irfpy.util import utc
import irfpy.vexpvat.vexspice as vs
vs.init()
from irfpy.vexpvat.ql import Panel_xr_orbit
2-a. To plot a simple, default figure
::
t0 = datetime.datetime(2006, 12, 1, 5, 0)
t1 = datetime.datetime(2006, 12, 1, 8, 0)
xrplot = Panel_xr_orbit(t0, t1)
2-b. To add some more data points, use the :meth:`add_orbit_curve`, :meth:`add_ticks`, :meth:`add_timelabel`.
::
t2 = datetime.datetime(2006, 12, 1, 14, 0)
t3 = datetime.datetime(2006, 12, 1, 16, 0)
xrplot.add_orbit_curve(t2, t3, color='b')
xrplot.add_ticks(utc.dtlinspace(t2, t3, 4), color='b', marker='x')
xrplot.add_timelabel(utc.dtlinspace(t2, t3, 4), color='b', datefmt='(%H:%M)', va='center', fontsize=6)
2-c. To add some cosmetics, use ``xrplot.ax`` as a normal matplotlib axis object.
::
ax = xrplot.ax
ax.set_xlim(-4, 4) # Change the limit, for example, as usual for matplotlib.
ax.text(0, 0, 'VENUS', color='k')
3. You can embed the panel to a figure.
::
fig = plt.figure()
ax = fig.add_subplot(2, 2, 2) # Plot goes to the top-right
xrplot2 = Panel_xr_orbit(ax=ax)
xrplot2.add_orbit_curve(t1, t2)
xrplot2.add_venus()
"""
def __init__(self, t0=None, t1=None, ax=None, frame='VSO'):
self.frame = frame
if ax is None:
self.ax = plt.gca()
else:
self.ax = ax
# If t0 and t1 is given, default sets of plots are produced.
if t0 is not None and t1 is not None:
self.add_orbit_curve(t0, t1)
self.add_ticks(utc.dtlinspace(t0, t1, 5))
self.add_timelabel(utc.dtlinspace(t0, t1, 5))
self.add_venus()
self.add_bs()
self.add_icb()
self.ax.set_aspect('equal')
self.ax.set_xlim(-6, 6)
self.ax.set_ylim(0, 12)
self.ax.set_xlabel('X [Rv; {}]'.format(frame))
self.ax.set_ylabel('R [Rv; {}]'.format(frame))
self.ax.set_title('VEX Orbit')
def _xr(self, tlist, target='VEX'):
poses = vs.get_positions(tlist, target=target, frame=self.frame, origin='VENUS')
x = poses[:, 0] / rv
r = np.sqrt(poses[:, 1] ** 2 + poses[:, 2] ** 2) / rv
return (x, r)
[docs] def add_orbit_curve(self, t0, t1, resolution=180, target='VEX', **kwds):
ax = self.ax
# dt = (t1 - t0).total_seconds()
# tlist = [t0 + datetime.timedelta(seconds=dt) * (i / (resolution - 1)) for i in range(resolution)]
from irfpy.util.utc import dtlinspace
tlist = dtlinspace(t0, t1, resolution)
x, r = self._xr(tlist, target=target)
ax.plot(x, r, **kwds)
[docs] def add_venus(self, facecolor='y', edgecolor='none', **kwds):
venus = mplpatches.Circle([0, 0], 1, facecolor=facecolor, edgecolor=edgecolor)
self.ax.add_patch(venus)
[docs] def add_ticks(self, tlist, target='VEX', marker='o', **kwds):
ax = self.ax
x, r = self._xr(tlist, target=target)
ax.plot(x, r, marker=marker, ls='none', **kwds)
[docs] def add_timelabel(self, tlist, target='VEX', datefmt=' %T', **kwds):
ax = self.ax
x, r = self._xr(tlist, target=target)
for _x, _r, _t in zip(x, r, tlist):
ax.text(_x, _r, _t.strftime(datefmt), **kwds)
[docs] def add_icb(self, ls=':', color='y', **kwds):
x, r = icb.xr_martinecz08()
self.ax.plot(x, r, ls=ls, color=color, **kwds)
[docs] def add_bs(self, ls=':', color='y', **kwds):
x, r = bowshock.xr_martinecz08()
self.ax.plot(x, r, ls=ls, color=color, **kwds)
[docs]def axis_object(t, target, ax=None, marker='o', color='k', **kwds):
""" Add a point to the axis!
:param t: Time
:param ax: Axis object
:param kwds: Given to axes.text function
:return: Axis object
"""
if ax is None:
ax = plt.gca()
vc = vs.get_position(t, target=target, origin='VEX', frame='VEX_ASPERA4_IMAS')
theta = np.rad2deg(np.arcsin(vc[2] / np.sqrt((vc ** 2).sum())))
phi = np.rad2deg(np.arctan2(vc[1], vc[0]))
# print(target, vc, theta, phi)
ax.plot([phi - 360, phi, phi + 360], [theta, theta, theta], marker=marker, color=color, ls='None', **kwds)
return ax, (phi, theta)
[docs]def axis_venus_limb(t, ax=None, color='y', **kwds):
if ax is None:
ax = plt.gca()
# Direction of venus
vc = vs.get_position(t, target='VENUS', origin='VEX', frame='VEX_ASPERA4_IMAS')
# theta = np.rad2deg(np.arcsin(vc[2] / np.sqrt((vc ** 2).sum())))
# phi = np.rad2deg(np.arctan2(vc[1], vc[0]))
vc_len = np.linalg.norm(vc)
venus_angle = np.arcsin(rv / vc_len)
#print('Venus angle:', np.rad2deg(venus_angle))
# Cone vectors
from irfpy.util import cone
vecs = cone.get_surface_vectors(vc, np.rad2deg(venus_angle), ndiv=60) # (3, 60) array
ts = []
ps = []
for vec in vecs.T:
t = np.rad2deg(np.arcsin(vec[2] / np.linalg.norm(vec)))
p = np.rad2deg(np.arctan2(vec[1], vec[0]))
#print(p, ps)
if len(ps) > 0 and np.abs(ps[-1] - p) > 180:
ts.append(np.nan)
ps.append(np.nan)
ts.append(t)
ps.append(p)
ts = np.array(ts)
ps = np.array(ps)
# print(ts, ps)
ax.plot(ps, ts, color=color, **kwds)
ax.plot(ps + 360, ts, color=color, **kwds)
ax.plot(ps - 360, ts, color=color, **kwds)
return ax, ()
[docs]def axis_venus_latitudes(t, latitudes=[-90, -60, -30, 0, 30, 60, 90], resolution=60, ax=None, color='y', **kwds):
if ax is None:
ax = plt.gca()
segments = []
# Position of VEX is (0, 0, 0), the observer
# Positoin of Venus is a center of sphere.
vc = vs.get_position(t, target='VENUS', origin='VEX', frame='VEX_ASPERA4_IMAS')
# Conversion matrix
matx = vs.convert_matrix(t, fromframe='IAU_VENUS', toframe='VEX_ASPERA4_IMAS')
for latitude_deg in latitudes:
latitude = np.deg2rad(latitude_deg)
longitudes = np.deg2rad(np.linspace(0, 360, resolution))
segment = []
for longitude in longitudes:
x = np.cos(longitude) * np.cos(latitude) * rv * 1.001 # Slightly bigger than rv to avoid numerical errors
y = np.sin(longitude) * np.cos(latitude) * rv * 1.001
z = np.sin(latitude) * rv * 1.001
target = matx.dot(np.array([x, y, z])) + vc
if isvisible([0, 0, 0], target, vc, rv):
theta = np.arcsin(target[2] / np.linalg.norm(target))
phi = np.arctan2(target[1], target[0])
segment.append([np.rad2deg(phi), np.rad2deg(theta)])
else:
segment.append([np.nan, np.nan]) # Not visible, not plotted
if not np.isnan(segment).all():
segments.append(np.array(segment))
for segment in segments:
ps = unjump_periodic(segment[:, 0], 360)
ts = segment[:, 1]
ax.plot(ps, ts, color=color, **kwds)
ax.plot(ps + 360, ts, color=color, **kwds)
ax.plot(ps - 360, ts, color=color, **kwds)
return ax, ()
[docs]def axis_venus_longitudes(t, longitudes=[-180, -135, -90, -45, 0, 45, 90, 135], resolution=45, ax=None, color='y', **kwds):
if ax is None:
ax = plt.gca()
segments = []
# Position of VEX is (0, 0, 0), the observer
# Positoin of Venus is a center of sphere.
vc = vs.get_position(t, target='VENUS', origin='VEX', frame='VEX_ASPERA4_IMAS')
# Conversion matrix
matx = vs.convert_matrix(t, fromframe='IAU_VENUS', toframe='VEX_ASPERA4_IMAS')
for longitude_deg in longitudes:
longitude = np.deg2rad(longitude_deg)
latitudes = np.deg2rad(np.linspace(-90, 90, resolution))
segment = []
for latitude in latitudes:
x = np.cos(longitude) * np.cos(latitude) * rv * 1.001 # Slightly bigger than rv to avoid numerical errors
y = np.sin(longitude) * np.cos(latitude) * rv * 1.001
z = np.sin(latitude) * rv * 1.001
target = matx.dot(np.array([x, y, z])) + vc
if isvisible([0, 0, 0], target, vc, rv):
theta = np.arcsin(target[2] / np.linalg.norm(target))
phi = np.arctan2(target[1], target[0])
segment.append([np.rad2deg(phi), np.rad2deg(theta)])
else:
segment.append([np.nan, np.nan]) # Not visible, not plotted
if not np.isnan(segment).all():
segments.append(np.array(segment))
for segment in segments:
ps = unjump_periodic(segment[:, 0], 360)
ts = segment[:, 1]
ax.plot(ps, ts, color=color, **kwds)
ax.plot(ps + 360, ts, color=color, **kwds)
ax.plot(ps - 360, ts, color=color, **kwds)
return ax, ()