<jupyter_start><jupyter_text>Day 8, Part 1 - intro to ipyvolumeWe'll start our journey into the 3RD DIMENSION with the package ```ipyvolume```<jupyter_code># if you don't get it:
#!pip install ipyvolume
# note: you may need:
#!jupyter nbextension enable --py --sys-prefix ipyvolume
#!jupyter nbextension enable --py --sys-prefix widgetsnbextension

# or you can do:
#!conda install -c conda-forge ipyvolume


import ipyvolume<jupyter_output><empty_output><jupyter_text>Let's do a quick look at something with some random 3D data:<jupyter_code>import numpy as np
x, y, z = np.random.random((3, 10000))
ipyvolume.quickscatter(x, y, z, size=1, marker="sphere")<jupyter_output><empty_output><jupyter_text>Easy peasy!  Let's read in our simulation data and plot this!<jupyter_code>from sys import path
path.append('../lesson02/')

from hermite_library import do_hermite
star_mass = 1.0 # stellar mass in Msun
planet_masses = np.array( [1.0, 0.05] ) # planet masses in Mjupiter

# [x,y,z] coords for each planet in AU
# NOTE: no z-coords!  These will be set to zero later on if you make them non-zero
planet_initial_position = np.array([ [5.0, 0.0, 6.0], 
                                     [10.0, 0.0, 3.0] ])

# planet's velocity at each position in km/s
# NOTE: no z-velocities!  These will be set to zero later on if you make them non-zero
planet_initial_velocity = np.array([ [0.0, 10.0, 1.0], 
                                     [0.0, -5.0, 0.0]])
# h is for hermite!
r_h, v_h, t_h, e_h = do_hermite(star_mass, 
                                planet_masses, 
                                planet_initial_position, 
                                planet_initial_velocity, 
                               tfinal=200, Nsteps=8800, 
                               threeDee=True)
# we'll have to reformat a bit for plotting
# right now, just all as one color
x = r_h[:,0,:].ravel()
y = r_h[:,1,:].ravel()
z = r_h[:,2,:].ravel()
ipyvolume.quickscatter(x, y, z, 
                       size=1, marker="sphere")<jupyter_output><empty_output><jupyter_text>Let's make things a little more complicated and allow us to take a look at each orbit:<jupyter_code>ipyvolume.figure()
colors = ['red', 'blue', 'green']
for i in range(r_h.shape[0]):
    ipyvolume.scatter(r_h[i,0,:],
                      r_h[i,1,:],
                      r_h[i,2,:], 
                      color=colors[i], 
                     marker='sphere')
ipyvolume.show()<jupyter_output><empty_output><jupyter_text>So, this is pretty cool - we can now see how the orbits "precess" during their evolution and we can check out these shapes in 3D. Note we can also plot more abstract spaces in 3D - like velocity space:<jupyter_code>ipyvolume.figure()
colors = ['red', 'blue', 'green']
for i in range(v_h.shape[0]):
    ipyvolume.scatter(v_h[i,0,:],
                      v_h[i,1,:],
                      v_h[i,2,:], 
                      color=colors[i],
                     marker='sphere')
ipyvolume.show()<jupyter_output><empty_output><jupyter_text>With this we can see how "jumpy" the velocity changes can get - this may be a numerical effect that is causing the precession of the orbits, or just how things are! Ok, we can also show velocity by little vectors:<jupyter_code>ipyvolume.figure()
colors = ['red', 'blue', 'green']
for i in range(v_h.shape[0]):
    ipyvolume.quiver(r_h[i,0,:],
                      r_h[i,1,:],
                      r_h[i,2,:],
                     v_h[i,0,:],
                      v_h[i,1,:],
                      v_h[i,2,:], 
                      color=colors[i])
ipyvolume.show()<jupyter_output><empty_output><jupyter_text>So clearly the above is pointless - while it looks cool the arrows are too big and there are too many of them!  We can change this by taking "X" number of points:<jupyter_code>step = 600
# also, length of arrays
N = v_h.shape[2]

ipyvolume.figure()
colors = ['red', 'blue', 'green']
for i in range(v_h.shape[0]):
    ipyvolume.quiver(r_h[i,0,0:N:step],
                      r_h[i,1,0:N:step],
                      r_h[i,2,0:N:step],
                     v_h[i,0,0:N:step],
                      v_h[i,1,0:N:step],
                      v_h[i,2,0:N:step], 
                      color=colors[i])
ipyvolume.show()<jupyter_output><empty_output><jupyter_text>Now we can see a bit more about the motion - that their directions are opposite of eachother for example.  And that the central mass only moves slightly and around its center as well.  AnimationLet's now figure out how to make an animation, and then save it for ourselves!  To do this, we'll need to format our data specifically as (time, position):<jupyter_code># for example, for particle 0:
r_h[:,0,:].T.shape
step = 10
# also, length of arrays
N = v_h.shape[2]

r = r_h[:,:,0:N:step]
v = v_h[:,:,0:N:step]

r_h.shape, r.shape, r[:,2,:].T.shape
# have to format color as well
#colors = np.empty((0,3))
color = [(1,0,0), (0,0,1), (0,1,0)]

#colors = np.array([])
colors = []
for i in range(r.shape[2]):
    colors.append(color)
    
colors = np.array(colors)

# order should be (times, points, colors)
colors = np.transpose(colors, (0, 2, 1)) # flip the last axes

colors.shape
ipyvolume.figure()

s = ipyvolume.scatter(r[:,0,:].T, r[:,1,:].T, r[:,2,:].T, 
                      marker='sphere', 
                     color=colors)

ani = ipyvolume.animation_control(s, interval=200)

ipyvolume.show()<jupyter_output><empty_output><jupyter_text>Note that we can only use the ```animation_control``` function on scatter plots or quiver plots, so we can't add lines or anything here.  Perhaps in a future release of ```ipyvolume```!  Saving animations as gifs - DON'T DO THIS ONENow if you have a nice animation you like, you can save it as a gif or other movie file!  To do that we have to set a "view" for our camera and then play our movie.  We can start with something simple. Suppose we like our current view above, let's try saving this with:<jupyter_code>myView = ipyvolume.view()

myView<jupyter_output><empty_output><jupyter_text>Then we generate a function that will set this view for all frames.  It will take in a few parameters that we will ignore:<jupyter_code>def set_view(figure, framenr, fraction):
    ipyvolume.view(myView[0], myView[1], myView[2])
#def set_view(figure, framenr, fraction):
#    ipyvolume.view(fraction*360, (fraction - 0.5) * 180, distance=2 + fraction*2)
#    s.size = size * (2+0.5*np.sin(fraction * 6 * np.pi))

#ipyvolume.movie('myMovie.gif', set_view, fps=20, frames=40)
#convert -delay 5.0 -loop 0 /var/folders/4h/rklzvjw
#!open myMovie.gif<jupyter_output>ERROR! Session/line number was not unique in database. History logging moved to new session 287<jupyter_text>Note: the above does nothing.   This is because the animations only are for changing angles of things, so bugger it.  Embedding<jupyter_code>import ipywidgets
myBox = ipywidgets.VBox([ani])
myBox
#ipyvolume.embed.embed_html("testEmbed.html", ani, offline=True, devmode=True)

#!open testEmbed.html
#ipyvolume.embed.embed_html?<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12382978723404256, 'fraction_numerical': 0.02099290780141844, 'mean_word_length': 3.0569620253164556, 'pattern_counts': {'":': 0, '<': 44, '<?xml version=': 0, '>': 44, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 1, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '11', 'dir': 'jupyter-structured-clean-dedup', 'id': '209954', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 2551, 'n_tokens_neox': 2415, 'n_words': 727, 'path': 'lesson08/_programming_ipyvolume_intro_lesson08_OLD.ipynb', 'repo_name': 'jnaiman/csci-p-14110_su2019', 'size': '7050'}