diff --git a/solarmach/__init__.py b/solarmach/__init__.py
index fe9fcbb..1e9e34c 100644
--- a/solarmach/__init__.py
+++ b/solarmach/__init__.py
@@ -1353,7 +1353,7 @@ def legend_arrow(width, height, **_):
if return_plot_object:
return fig, ax
- def pfss_3d(self, active_area=(None, None, None, None), color_code='object'):
+ def pfss_3d(self, active_area=(None, None, None, None), color_code='object', rss=2.5, zoom_out=False):
"""
https://plotly.github.io/plotly.py-docs/generated/plotly.graph_objects.Scatter3d.html
https://plotly.com/python-api-reference/generated/plotly.graph_objects.Figure.html
@@ -1521,6 +1521,269 @@ def pfss_3d(self, active_area=(None, None, None, None), color_code='object'):
width=1280, height=720,
margin=dict(r=20, l=10, b=10, t=10))
+ # """START"""
+ # fig.update_layout(scene=dict(
+ # xaxis=dict(nticks=4, range=[-220, 220],),
+ # yaxis=dict(nticks=4, range=[-220, 220],),
+ # zaxis=dict(nticks=4, range=[-220, 220],),),
+ # width=1280, height=720,
+ # margin=dict(r=20, l=10, b=10, t=10))
+ # for i, body_id in enumerate(self.body_dict):
+ # body_lab = self.body_dict[body_id][1]
+ # body_color = self.body_dict[body_id][2]
+ # body_vsw = self.body_dict[body_id][4]
+ # body_pos = self.body_dict[body_id][3]
+
+ # # print(body_pos.cartesian.x.to(u.solRad), body_pos.cartesian.y.to(u.solRad), body_pos.cartesian.z.to(u.solRad))
+
+ # # pos = body_pos
+ # # dist_body = pos.radius.value
+
+ # # body_long = pos.lon.value
+ # # body_lat = pos.lat.value
+
+ # # take into account solar differential rotation wrt. latitude
+ # # omega = self.solar_diff_rot(body_lat)
+
+ # print(body_pos.cartesian.x.to(u.solRad).value, body_pos.cartesian.y.to(u.solRad).value, body_pos.cartesian.z.to(u.solRad).value)
+
+ # str_number = None
+ # # x, y, z = spheric2cartesian(dist_body*np.cos(np.deg2rad(body_lat)), np.deg2rad(body_long), np.deg2rad(body_lat))
+ # # x, y, z = spheric2cartesian(dist_body*np.cos(np.deg2rad(body_lat)), np.deg2rad(body_lat), np.deg2rad(body_long))
+ # # x, y, z = spheric2cartesian(dist_body, np.deg2rad(body_long), np.deg2rad(body_lat))
+ # # x = r*np.cos(theta) *np.sin(phi)
+ # # y = r*np.sin(theta)*np.sin(phi)
+ # # z= r*np.cos(phi)
+ # fig.add_trace(go.Scatter3d(
+ # x=[body_pos.cartesian.x.to(u.solRad).value],
+ # y=[body_pos.cartesian.y.to(u.solRad).value],
+ # z=[body_pos.cartesian.z.to(u.solRad).value],
+ # mode='markers+text',
+ # name=body_id,
+ # marker=dict(size=16, color=body_dict[body_id][2]),
+ # # text=[f'{body_id}'],
+ # # textposition="top center",
+ # text=[str_number],
+ # textfont=dict(color="white", size=14),
+ # textposition="middle center",
+ # # thetaunit="radians"
+ # ))
+ # """STOP"""
+ numbered_markers = True
+ plot_spirals = True
+ plot_sun_body_line = True
+
+ AU = const.au / 1000 # km
+
+ # scale from AU/km to solar radii/km
+ # r_array = r_array * AU / R_sun.to(u.km).value
+ max_dist2 = self.max_dist * AU / R_sun.to(u.km).value
+
+ # TODO: is r_array falsly projected to the ecliptic here again???
+ # build array of values for radius (in spherical coordinates!) given in AU!
+ # r_array = np.arange(0.007, (self.max_dist+0.1)/np.cos(np.deg2rad(self.max_dist_lat)) + 3.0, 0.001)
+ # r_array = np.arange(0.007, (max_dist2+0.1)/np.cos(np.deg2rad(self.max_dist_lat)) + 3.0, 0.001) # Define with lower "resolution"!
+ r_array = np.arange(0.007, (max_dist2+0.1)/np.cos(np.deg2rad(self.max_dist_lat)) + 3.0, 0.05)
+
+ for i, body_id in enumerate(self.body_dict):
+ body_lab = self.body_dict[body_id][1]
+ body_color = self.body_dict[body_id][2]
+ body_vsw = self.body_dict[body_id][4]
+ body_pos = self.body_dict[body_id][3]
+
+ pos = body_pos
+ # dist_body = pos.radius.value
+ dist_body = (pos.radius.to(u.m)/R_sun).value
+
+ body_long = pos.lon.value
+ body_lat = pos.lat.value
+
+ # take into account solar differential rotation wrt. latitude
+ omega = self.solar_diff_rot(body_lat)
+
+ # TODO: np.cos(np.deg2rad(body_lat) correct????
+ # alpha_body = np.deg2rad(body_long) + omega / (body_vsw / AU) * (dist_body - r_array) * np.cos(np.deg2rad(body_lat))
+ alpha_body = np.deg2rad(body_long) + omega / (body_vsw / R_sun.to(u.km).value) * (dist_body - r_array) * np.cos(np.deg2rad(body_lat))
+
+ if plot_spirals:
+ phi = np.ones(len(r_array))*np.deg2rad(body_lat)
+ # x, y, z = spheric2cartesian(r_array * np.cos(np.deg2rad(body_lat)), phi, alpha_body)
+ x, y, z = spheric2cartesian(r_array[r_array>=rss], phi[r_array>=rss], alpha_body[r_array>=rss])
+
+ fig.add_trace(go.Scatter3d(x=x,
+ y=y,
+ z=z,
+ mode='lines',
+ name=f'{body_id} magnetic field line',
+ showlegend=False,
+ line=dict(color=body_dict[body_id][2]),
+ # thetaunit="radians"
+ ))
+
+ if plot_sun_body_line:
+ x, y, z = spheric2cartesian([0.01, dist_body], [0.01, np.deg2rad(body_lat)], [np.deg2rad(body_long), np.deg2rad(body_long)])
+
+ fig.add_trace(go.Scatter3d(x=x,
+ y=y,
+ z=z,
+ mode='lines',
+ name=f'{body_id} direct line',
+ showlegend=False,
+ line=dict(color=body_dict[body_id][2], dash='dot'),
+ # thetaunit="radians"
+ ))
+
+ if numbered_markers:
+ str_number = f'{i+1}'
+ else:
+ str_number = None
+
+ fig.add_trace(go.Scatter3d(x=[(body_pos.cartesian.x.to(u.m)/R_sun).value],
+ y=[(body_pos.cartesian.y.to(u.m)/R_sun).value],
+ z=[(body_pos.cartesian.z.to(u.m)/R_sun).value],
+ mode='markers+text',
+ name=body_id,
+ marker=dict(size=10, color=body_dict[body_id][2]),
+ # text=[f'{body_id}'],
+ text=[str_number],
+ textfont=dict(color="white", size=14),
+ textposition="middle center",
+ # thetaunit="radians"
+ ))
+
+ xyz_range = 2.5
+ if zoom_out:
+ xyz_range = max_dist2
+
+ fig.update_layout(scene=dict(xaxis=dict(title="X / R_sun", nticks=4, range=[-xyz_range, xyz_range],),
+ yaxis=dict(title="Y / R_sun", nticks=4, range=[-xyz_range, xyz_range],),
+ zaxis=dict(title="Z / R_sun", nticks=4, range=[-xyz_range, xyz_range],)),
+ width=1280, height=720,
+ margin=dict(r=20, l=10, b=10, t=10),
+ )
+
+ fig.add_trace(go.Surface(x=np.linspace(-200, 200, 100),
+ y=np.linspace(-200, 200, 100),
+ z=np.zeros((100, 100)),
+ hoverinfo='skip',
+ colorscale='gray', showscale=False, opacity=0.2))
+
+ if _isstreamlit():
+ fig.update_layout(width=700, height=700)
+ import streamlit as st
+ # st.plotly_chart(pfig, theme="streamlit")
+ st.components.v1.html(fig.to_html(include_mathjax='cdn'), height=700)
+ else:
+ fig.show()
+
+ return
+
+ def plot_3d(self, plot_spirals=True, plot_sun_body_line=True, numbered_markers=True):
+ """
+ experimental 3d version of classic solarmach plot (no pfss)
+ """
+
+ import plotly.express as px
+ import plotly.graph_objects as go
+ from astropy.constants import R_sun
+ from plotly.graph_objs.scatter3d import Line
+
+ AU = const.au / 1000 # km
+ # sun_radius = aconst.R_sun.value # meters
+
+ # build array of values for radius (in spherical coordinates!) given in AU!
+ r_array = np.arange(0.007, (self.max_dist+0.1)/np.cos(np.deg2rad(self.max_dist_lat)) + 3.0, 0.001)
+
+ # create the sun object, a sphere, for plotting
+ # use 10*R_sun to have it visilble!
+ sun = sphere(radius=(10*u.solRad).to(u.AU).value, clr='#ffff55') # '#ffff00'
+
+ # create the figure
+ fig = go.Figure([sun])
+
+ # additional figure settings, like aspect mode, extreme values of axes etc...
+ fig.update_layout(scene_aspectmode='cube')
+
+ fig.update_layout(scene=dict(xaxis=dict(title="X / AU", nticks=4, range=[-self.max_dist, self.max_dist],),
+ yaxis=dict(title="Y / AU", nticks=4, range=[-self.max_dist, self.max_dist],),
+ zaxis=dict(title="Z / AU", nticks=4, range=[-self.max_dist, self.max_dist],)),
+ width=1280, height=720,
+ margin=dict(r=20, l=10, b=10, t=10),
+ )
+
+ for i, body_id in enumerate(self.body_dict):
+ body_lab = self.body_dict[body_id][1]
+ body_color = self.body_dict[body_id][2]
+ body_vsw = self.body_dict[body_id][4]
+ body_pos = self.body_dict[body_id][3]
+
+ pos = body_pos
+ dist_body = pos.radius.value
+
+ body_long = pos.lon.value
+ body_lat = pos.lat.value
+
+ # take into account solar differential rotation wrt. latitude
+ omega = self.solar_diff_rot(body_lat)
+
+ # TODO: np.cos(np.deg2rad(body_lat) correct????
+ alpha_body = np.deg2rad(body_long) + omega / (body_vsw / AU) * (dist_body - r_array) * np.cos(np.deg2rad(body_lat))
+
+ if plot_spirals:
+ phi = np.ones(len(r_array))*np.deg2rad(body_lat)
+ # x, y, z = spheric2cartesian(r_array * np.cos(np.deg2rad(body_lat)), phi, alpha_body)
+ x, y, z = spheric2cartesian(r_array, phi, alpha_body)
+
+ fig.add_trace(go.Scatter3d(x=x,
+ y=y,
+ z=z,
+ mode='lines',
+ name=f'{body_id} magnetic field line',
+ showlegend=False,
+ line=dict(color=body_dict[body_id][2]),
+ # thetaunit="radians"
+ ))
+
+ if plot_sun_body_line:
+ x, y, z = spheric2cartesian([0.01, dist_body], [0.01, np.deg2rad(body_lat)], [np.deg2rad(body_long), np.deg2rad(body_long)])
+
+ fig.add_trace(go.Scatter3d(x=x,
+ y=y,
+ z=z,
+ mode='lines',
+ name=f'{body_id} direct line',
+ showlegend=False,
+ line=dict(color=body_dict[body_id][2], dash='dot'),
+ # thetaunit="radians"
+ ))
+
+ if numbered_markers:
+ str_number = f'{i+1}'
+ else:
+ str_number = None
+
+ # customdata=[[dist_body], [body_long], [body_lat]]
+ fig.add_trace(go.Scatter3d(x=[body_pos.cartesian.x.value],
+ y=[body_pos.cartesian.y.value],
+ z=[body_pos.cartesian.z.value],
+ mode='markers+text',
+ name=body_id,
+ marker=dict(size=10, color=body_dict[body_id][2]),
+ # text=[f'{body_id}'],
+ text=[str_number],
+ textfont=dict(color="white", size=14),
+ textposition="middle center",
+ # customdata=[[dist_body], [body_long], [body_lat]],
+ # hovertemplate='r:%{customdata[0]:.3f}
t: %{customdata[1]:.3f}
p: %{customdata[2]:.3f} ',
+ # thetaunit="radians"
+ ))
+
+ fig.add_trace(go.Surface(x=np.linspace(-200, 200, 100),
+ y=np.linspace(-200, 200, 100),
+ z=np.zeros((100, 100)),
+ hoverinfo='skip',
+ colorscale='gray', showscale=False, opacity=0.2))
+
if _isstreamlit():
fig.update_layout(width=700, height=700)
import streamlit as st