<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
from solverlibs import read_in_galaxy_data
# time (N-body units), position vectors at each time (kpc), 
#  velocity vectors (km/s), energy (N-body units), # bodies, particle type (dark matter or stars)
# make sure you link were things are saved
save_file = '/Users/jillnaiman/csci-p-14110/lesson08/data/outarrsnap_001_fac1n3.txt'
t_h, r_h, v_h, E_h, N, part_type = read_in_galaxy_data(save_file)
r_h.shape
# 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")
# this plots things as overlapping spheres
# so the orbits look like tubes<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'] # now velocity of each particle is different color
for i in range(v_h.shape[0]): # loop over number of particles
    ipyvolume.scatter(v_h[i,0,:],
                      v_h[i,1,:],
                      v_h[i,2,:],
                     marker='sphere')
ipyvolume.show()<jupyter_output><empty_output><jupyter_text>So this is a little less intiative, but this is how the velocities of our particles change during their orbits. Ok, we can also show velocity by little vectors:<jupyter_code>ipyvolume.figure()
for i in range(v_h.shape[0]): # loop over particles 
    ipyvolume.quiver(r_h[i,0,:], # plot x,y,z positions
                      r_h[i,1,:],
                      r_h[i,2,:],
                     v_h[i,0,:], # also include vx/vy/vz vectors of velocities
                      v_h[i,1,:],
                      v_h[i,2,:])
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.  This is like the subsampling we did before to keep our framerates of our animations small:<jupyter_code>step = 1000 # plot ever "step"th velocity vector
# also, length of arrays in time-axis
N = v_h.shape[2]

ipyvolume.figure()
for i in range(v_h.shape[0]): # loop every particle
    ipyvolume.quiver(r_h[i,0,0:N:step], # plot subsampled x/y/z
                      r_h[i,1,0:N:step],
                      r_h[i,2,0:N:step],
                     v_h[i,0,0:N:step], # with subsampled vectors vx/vy/vz
                      v_h[i,1,0:N:step],
                      v_h[i,2,0:N:step], 
                     size=2) # also, if things look too crowded, we can also make the arrows themselves smaller
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 in 3D, 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 # only do every 10 steps
# also, length of arrays in time
N = v_h.shape[2]

# subsample to make more managable
r = r_h[:,:,0:N:step]
v = v_h[:,:,0:N:step]

r_h.shape, r.shape, r[:,2,:].T.shape
ipyvolume.figure()

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

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```!  ExerciseTry higher resolution in time.Try a higher resolution dataset.  Part 2: ipyvolume + ipywidgetsNow let's combine the powers of widgets and ipyvolume to explore our datasets in 3D.<jupyter_code>import ipywidgets
step = 100 # only do every 100th timestep
# also, length of arrays
N = v_h.shape[2] # full time

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

r[:,0,:].ravel().shape
ipyvolume.figure()

x = r[:,0,:].ravel()
y = r[:,1,:].ravel()
z = r[:,2,:].ravel()

s = ipyvolume.scatter(x, y, z, 
                      marker='sphere')

#ipyvolume.show()
#colors.shape, r[:,0,:].shape<jupyter_output><empty_output><jupyter_text>Now let's use widgets to change the size and color of our points:<jupyter_code>import ipywidgets
size = ipywidgets.FloatSlider(min=0, max=30, step=0.1)
color = ipywidgets.ColorPicker()<jupyter_output><empty_output><jupyter_text>Now we'll use a function we haven't used before from ipywidgets - something that links our scatter plot features to our widgets:<jupyter_code>ipywidgets.jslink((s, 'size'), (size, 'value'))
ipywidgets.jslink((s, 'color'), (color, 'value'))<jupyter_output><empty_output><jupyter_text>Finally, well put all these things in a row: our plot, then our two linked widgets:<jupyter_code>ipywidgets.VBox([ipyvolume.gcc(), size,  color])<jupyter_output><empty_output><jupyter_text>ExerciseBonus: make a quiver plotBonus: what other things can you think to add sliders/pickers for?  Hint: check out the docs for ```ipyvolume.quiver``` and ```ipyvolume.scatter``` to see what you can change.  Part 3 - embeddingFinally, we might want to embed our creations on the web somewhere.  The first step is to make an ```html``` file from our in-python widgets.  Luckily, there is a function for that!<jupyter_code>myVBox = ipywidgets.VBox([ipyvolume.gcc(), size,  color])
# if we don't do this, the bqplot will be really tiny in the standalone html
ipyvolume.embed.layout = myVBox.children[1].layout
ipyvolume.embed.layout.min_width = "400px"
# NOTE: try offline=False if any dispaly issues come up
ipyvolume.embed.embed_html("myPage_galaxies.html", myVBox, offline=True, devmode=False)
!open myPage_galaxies.html<jupyter_output><empty_output><jupyter_text>ExerciseGenerate a page for your own simulation with all the controls you want!**Bonus**: though we won't be covering it explicitly, you can actually deploy this to the web to be hosted on github pages.  The first thing you need to do is call ```embed``` a little differently:<jupyter_code>ipyvolume.embed.embed_html("myPage_galaxies.html", myVBox, offline=False, devmode=False)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11803616051741879, 'fraction_numerical': 0.013523445538732913, 'mean_word_length': 4.0890052356020945, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 45, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '11', 'dir': 'jupyter-structured-clean-dedup', 'id': '30235', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 2412, 'n_tokens_neox': 2305, 'n_words': 737, 'path': 'lesson08/Optional_galaxiesIn3D.ipynb', 'repo_name': 'jnaiman/csci-p-14110_su2019', 'size': '6803'}