class OrbitPlotter3D(_PlotlyOrbitPlotter): """OrbitPlotter3D class.""" def __init__(self, figure=None, dark=False, *, num_points=150, plane=None): super().__init__(figure, num_points=num_points, plane=plane) self._layout = Layout( autosize=True, scene=dict( xaxis=dict(title="x (km)"), yaxis=dict(title="y (km)"), zaxis=dict(title="z (km)"), aspectmode="data", # Important! ), ) if dark: self._layout.template = "plotly_dark" def _draw_point(self, radius, color, name, center=[0, 0, 0] * u.km): # We use _plot_sphere here because it's not easy to specify the size of a marker # in data units instead of pixels, see # https://stackoverflow.com/q/47086547 return self._draw_sphere(radius, color, name, center) def _draw_sphere(self, radius, color, name, center=[0, 0, 0] * u.km): xx, yy, zz = generate_sphere(radius, center) sphere = Surface( x=xx.to(u.km).value, y=yy.to(u.km).value, z=zz.to(u.km).value, name=name, colorscale=[[0, color], [1, color]], cauto=False, cmin=1, cmax=1, showscale=False, ) self._figure.add_trace(sphere) return sphere def _plot_coordinates(self, coordinates, label, colors, dashed): trace = Scatter3d( x=coordinates.x.to(u.km).value, y=coordinates.y.to(u.km).value, z=coordinates.z.to(u.km).value, name=label, line=dict(color=colors[0], width=5, dash="dash" if dashed else "solid"), mode="lines", # Boilerplate ) self._figure.add_trace(trace) return trace, [trace.line.color] def plot(self, orbit, *, label=None, color=None, trail=False): """Plots state and osculating orbit in their plane. Parameters ---------- orbit : ~poliastro.twobody.orbit.Orbit Orbit to plot. label : string, optional Label of the orbit. color : string, optional Color of the line and the position. trail : bool, optional Fade the orbit trail, default to False. """ if trail: raise NotImplementedError("trail not supported yet") return super().plot(orbit, label=label, color=color, trail=trail) @u.quantity_input(elev=u.rad, azim=u.rad, distance=u.km) def set_view(self, elev, azim, distance=5 * u.km): """Changes 3D view.""" x = distance * np.cos(elev) * np.cos(azim) y = distance * np.cos(elev) * np.sin(azim) z = distance * np.sin(elev) self._layout.update({ "scene": { "camera": { "eye": { "x": x.to(u.km).value, "y": y.to(u.km).value, "z": z.to(u.km).value, } } } }) if not self._figure._in_batch_mode: return self.show()
class OrbitPlotter3D(BaseOrbitPlotter): """OrbitPlotter3D class. """ def __init__(self, figure=None, dark=False): super().__init__(figure) self._layout = Layout( autosize=True, scene=dict( xaxis=dict(title="x (km)"), yaxis=dict(title="y (km)"), zaxis=dict(title="z (km)"), aspectmode="data", # Important! ), ) if dark: self._layout.template = "plotly_dark" def _plot_point(self, radius, color, name, center=[0, 0, 0] * u.km): # We use _plot_sphere here because it's not easy to specify the size of a marker # in data units instead of pixels, see # https://stackoverflow.com/q/47086547 return self._plot_sphere(radius, color, name, center) def _plot_sphere(self, radius, color, name, center=[0, 0, 0] * u.km): xx, yy, zz = generate_sphere(radius, center) sphere = Surface( x=xx.to(u.km).value, y=yy.to(u.km).value, z=zz.to(u.km).value, name=name, colorscale=[[0, color], [1, color]], cauto=False, cmin=1, cmax=1, showscale=False, ) self._figure.add_trace(sphere) return sphere def _plot_trajectory(self, trajectory, label, color, dashed): trace = Scatter3d( x=trajectory.x.to(u.km).value, y=trajectory.y.to(u.km).value, z=trajectory.z.to(u.km).value, name=label, line=dict(color=color, width=5, dash="dash" if dashed else "solid"), mode="lines", # Boilerplate ) self._figure.add_trace(trace) return trace @u.quantity_input(elev=u.rad, azim=u.rad, distance=u.km) def set_view(self, elev, azim, distance=5 * u.km): x = distance * np.cos(elev) * np.cos(azim) y = distance * np.cos(elev) * np.sin(azim) z = distance * np.sin(elev) self._layout.update({ "scene": { "camera": { "eye": { "x": x.to(u.km).value, "y": y.to(u.km).value, "z": z.to(u.km).value, } } } }) if not self._figure._in_batch_mode: return self.show()