Sage Days 9 -- 3d Graphics in Sage
system:sage

<font color='purple'><h1 align=center>Easy Lickable 3D Graphics in Sage, a Tutorial</h1></font>

<center><img src="lick.png"></center>

<br><br>
<br><br><br><br>
<br><br>
<br><br>
<hr>
<font color='black'><h1  align=center>Background</h1></font>
<br><br><br>

Robert Bradshaw and I added systematic 3d graphics support to Sage in January 2008, so 3d graphics are fairly new in Sage.
Nonetheless, they are very useful. 

<ol>
<li> Sage 3d graphics are built up from <b>three components</b>:
<ol> 
<li> <b>User Interface:</b> (my talk today) Python functions with lots of options that users directly call to easily create 3d scenes.
(I wrote most of this.)
<br><br>
<li> <b>3d "Subsystem":</b> (Robert Bradshaw's talk today) A cython library that converts the wishes of the user into low-level
primitives that make sense to various rendering systems.  This is where a lot of the interesting mathematics is.
(Robert Bradshaw wrote most of this.)
<br><br>
<li> <b>Rendering System:</b> Program that displays or renders an image expressed in some standard format, e.g., an X3d viewer,
a ray tracer, or a java applet. 
</ol>
<br><br>

<li> Sage mainly uses two systems to render 3d graphics, though other options are supported:
<ol>
<li> <a href="http://jedi.ks.uiuc.edu/%7Ejohns/raytracer/">Tachyon3d</a> -- a lightweight BSD-licensed multithreaded ray tracer (is the Tachyon web page gone? is the project dead???)  This is good because it is essentially the <b>only</b> fully open source program we could find that doesn't require an X server and quickly renders 3d images as png's. 
<br><br>

<li> <a href="http://jmol.sourceforge.net/">Jmol: an open-source Java viewer for chemical structures in 3D</a> -- this was meant for molecular visualization, but we adapted it for Sage.  It is GPL licensed.  Here is <a target="_new" href="http://jmol.sourceforge.net/demo/vibration/">an example of the sort of thing jmol can do, and which Sage could <i>certainly</i> do given some effort</a>. 

</ol>
<br><br>

<li> <b>Mayavi -- The High End Option for OpenGL-based 3d graphics in Sage/Python</b>
 <a href="http://mayavi.sourceforge.net/" target="_new">Mayavi / vtk</a> -- this is a powerful high-end setup for doing 3d accelerated graphics with Python.  It doesn't work over the web at all, but <i>does</i> take advantage of fast 3d accelerated graphics cards and can render very large data sets.  I don't use it, but many people do.   There are <a href="http://sagemath.org/packages/experimental/">experimental packages here</a> that
might allow you to easily build this visualization stack into Sage.   <b>Possible student project:</b> test those packages, update them, get them
up to "optional" quality. 
<ol>


<br><br>
<br><br>
<br><br><br><br>
<br><br>
<br><br>
<hr>

<font color='black'><h1  align=center>Demo: Cape Man</h1></font>
<br><br><br>

{{{id=1|
# Draw a nice yellow sphere, which is a basic primitive
S = sphere(size=.5, color='yellow')
S
///
}}}

{{{id=2|
# Get rid of the default frame
# All options to sphere that aren't specifically for a sphere get passed on to
# the show command, and also get carried along when you add objects with +. 
# This was a convenience I added for 3d graphics.  It's not in 2d graphics.
# Someone could implement this...
S = sphere(size=.5, color='yellow',    frame=False)
S
///
}}}

{{{id=3|
# There are a bunch more primitive shapes that you can see using sage.plot.plot3d.shapes.[tab]
C = sage.plot.plot3d.shapes.Cone(.5, .5, color='red')
C
///
}}}

{{{id=4|
# You can move a shape around (notice the z axis range below)
C = C.translate(0,0,0.3)   # (dx,dy,dz)
C   # this is now moved up.
///
}}}

{{{id=5|
# We can draw a bunch of sphere's with different colors and sizes
balls = sphere((.45,-.1,.15), size=.1, color='white') + sphere((.51,-.1,.17), size=.05, color='black')
balls += sphere((.45, .1,.15),size=.1, color='white') + sphere((.51, .1,.17), size=.05, color='black')
balls += sphere((.5,0,-.2),size=.1, color='yellow', aspect_ratio=[1,1,1], frame=False)
balls
///
}}}

{{{id=6|
# We plot a symbolic expression that is a function of two variables.
# Notice that the default frame is not a cube, i.e., not as tall as
# it is wide.  This just copies the default used in other Ma's, which
# is convenient for plotting functions.

var('x,y')
f = exp(x/5) * cos(y)
P = plot3d(f,(x,-5,5),(y,-5,5), adaptive=True, color=['red','yellow'])
P
///
}}}

{{{id=7|
# Now we combine all the above plots together in one image
cm = P.scale(.2) + (balls + C + S).translate(1,0,0)
cm.show(spin=True, zoom=1.1)
///
}}}

{{{id=8|

///
}}}

{{{id=9|

///
}}}

{{{id=10|

///
}}}

<br><br>
<br><br>
<br><br><br><br>
<br><br>
<br><br>
<hr>

<font color='black'><h1 align=center>Plotting Platonic Polytopes</h1></font>
<br><br><br>

{{{id=12|
show(tetrahedron(opacity=0.4) + tetrahedron(size=.5,color='red',center=(0,0,-0.1)), frame=False)
///
}}}

{{{id=13|
sum(tetrahedron(center=(i^2,0,i),color=hue(i/3)) for i in [0,0.2,..,2])
///
}}}

{{{id=14|
def f(number_of_tetrahedrons=(3,[1..5]), opacity=(0.6,(0.1,1))):
    v = (sqrt(5.)/2-5/6, 5/6*sqrt(3.)-sqrt(15.)/2, sqrt(5.)/3)
    t = acos(sqrt(5.)/3)/2
    tt = (tetrahedron(aspect_ratio=(1,1,1), opacity=opacity).rotateZ(t),
          tetrahedron(color='red', opacity=opacity).rotateZ(t).rotate(v,2*pi/5),
          tetrahedron(color='green', opacity=opacity).rotateZ(t).rotate(v,4*pi/5),
          tetrahedron(color='yellow', opacity=opacity).rotateZ(t).rotate(v,6*pi/5),
          tetrahedron(color='orange', opacity=opacity).rotateZ(t).rotate(v,8*pi/5))    
    show(sum(tt[:number_of_tetrahedrons]), frame=False, zoom=1.3)

f(5,0.6)
///
}}}

{{{id=15|
cube()
///
}}}

{{{id=16|
v = [(random(), random(), random()) for _ in [1..60]]
sum([cube((10*a,10*b,10*c), size=random()/3, color=(a,b,c)) for a,b,c in v])
///
}}}

{{{id=17|
show(cube(color=['red', 'blue', 'green'], frame_thickness=15, \
                       frame_color='brown', opacity=0.7), frame=False)
///
}}}

{{{id=18|
octahedron()
///
}}}

{{{id=19|
dodecahedron()
///
}}}

{{{id=20|
icosahedron(color='red')
///
}}}

{{{id=21|

///
}}}

{{{id=22|

///
}}}

<br><br>
<br><br>
<br><br><br><br>
<br><br>
<br><br>
<hr>

<font color='black'><h1  align=center>Lines, Text, Frames, Points,  </h1></font>
<br><br><br>

{{{id=24|
line3d([(1,2,3), (1,0,-2), (3,1,4), (2,1,-2)], color='red')
///
}}}

{{{id=25|
def tetra(col): 
    return line3d([(0,0,1), (2*sqrt(2.)/3,0,-1./3), (-sqrt(2.)/3, sqrt(6.)/3,-1./3),\ 
    (-sqrt(2.)/3,-sqrt(6.)/3,-1./3), (0,0,1), (-sqrt(2.)/3, sqrt(6.)/3,-1./3),\
    (-sqrt(2.)/3,-sqrt(6.)/3,-1./3), (2*sqrt(2.)/3,0,-1./3)],\
    color=col, thickness=10, aspect_ratio=[1,1,1])

v  = (sqrt(5.)/2-5/6, 5/6*sqrt(3.)-sqrt(15.)/2, sqrt(5.)/3)
t  = acos(sqrt(5.)/3)/2
t1 = tetra('blue').rotateZ(t)
t2 = tetra('red').rotateZ(t).rotate(v,2*pi/5)
t3 = tetra('green').rotateZ(t).rotate(v,4*pi/5)
t4 = tetra('yellow').rotateZ(t).rotate(v,6*pi/5)
t5 = tetra('orange').rotateZ(t).rotate(v,8*pi/5)
show(t1+t2+t3+t4+t5, frame=False, zoom=1.3)
///
}}}

{{{id=26|
v = finance.fractional_brownian_motion_simulation(0.9,0.01,1000,3)
line3d([(v[0][i],v[1][i],v[2][i]) for i in range(len(v[0]))], color='black')
///
}}}

{{{id=27|
sum(text("Hi, from Sage Days %s"%i, (i^2,i,i^3), color=(1-i/9,0,i/9)) for i in [1..9])
///
}}}

{{{id=28|
point3d([(random(), random()^2, random()^3) for _ in range(100)])
///
}}}

{{{id=29|

///
}}}

{{{id=30|

///
}}}

{{{id=31|

///
}}}

<br><br>
<br><br>
<br><br><br><br>
<br><br>
<br><br>
<hr>

<font color='black'><h1 align=center>Plotting a Piecewise-defined Function</h1></font>
<br><br><br>

{{{id=33|
def f(u,v):
   if u>=0.0 and v>=0.0:
       return arctan(abs(v/u)) 
   if u<0.0 and v>=0.0:
       return pi-arctan(abs(v/u))
   if u<0.0 and v<0.0:
       return pi+arctan(abs(v/u))
   if u>=0.0 and v<0.0:
       return 2*pi-arctan(abs(v/u))

plot3d(f,(-3,3),(-3,3), color=Color('#ffa000'))
///
}}}

{{{id=34|

///
}}}

{{{id=35|

///
}}}

{{{id=36|

///
}}}

<font color='darkgreen'><h1 align=center>3D Parametric Plots</h1></font>

{{{id=38|
var('u')
parametric_plot3d( (sin(u), cos(u), u/10), (u, 0, 20))
///
}}}

{{{id=39|
# The plot3d function, which plots a function f(x,y) really justs calls parametric_plot 
# (unless you specificaly ask to do adaptive refinement).
var('x,y')

plot3d(x*y*sin(10*x*cos(y)), (x,-1,1), (y,-1,1))
///
}}}

{{{id=40|
var('u,v')
fx = (3*(1+sin(v)) + 2*(1-cos(v)/2)*cos(u))*cos(v)
fy = (4+2*(1-cos(v)/2)*cos(u))*sin(v)
fz = -2*(1-cos(v)/2) * sin(u)
parametric_plot3d([fx, fy, fz], (u, 0, 2*pi), (v, 0, 2*pi), frame=False, color="green", opacity=.7)
///
}}}

{{{id=41|

///
}}}

{{{id=42|

///
}}}

{{{id=43|

///
}}}

<font color='darkgreen'><h1 align=center>3D List Plots</h1></font>

{{{id=45|
pi = float(pi)
m = matrix(RDF, 6, [sin(i^2 + j^2) for i in [0,pi/5,..,pi] for j in [0,pi/5,..,pi]])
list_plot3d(m, texture='yellow', frame_aspect_ratio=[1,1,1/3])
///
}}}

{{{id=46|
# We can change the interpolation type
list_plot3d(m, texture='yellow', interpolation_type='nn',frame_aspect_ratio=[1,1,1/3])
///
}}}

{{{id=47|
# We can make this look better by increasing the number of samples
list_plot3d(m, texture='yellow', interpolation_type='nn',frame_aspect_ratio=[1,1,1/3],num_points=40)
///
}}}

{{{id=48|
# Lets try a spline    
list_plot3d(m, texture='yellow', interpolation_type='spline',frame_aspect_ratio=[1,1,1/3], degree=5)
///
}}}

{{{id=49|
# Note that the points do not have to be regularly sampled. For example

l=[]
for i in range(-5,5):
    for j in range(-5,5):
        l.append((normalvariate(0,1),normalvariate(0,1),normalvariate(0,1)))
       
list_plot3d(l,interpolation_type='nn',texture='yellow',num_points=100)
///
}}}

{{{id=50|

///
}}}

{{{id=51|

///
}}}