First we set up the notebook to display mathematical objects using LaTeX formatting:
%display latex
We declare $\mathbb{S}^2$ as a differentiable manifold of dimension 2 over $\mathbb{R}$ and endow it with the stereographic charts from the North pole (stereoN
) and the South pole (stereoS
):
S2 = Manifold(2, 'S^2', latex_name=r'\mathbb{S}^2', start_index=1)
U = S2.open_subset('U')
V = S2.open_subset('V')
S2.declare_union(U, V)
stereoN.<x,y> = U.chart()
stereoS.<xp,yp> = V.chart(r"xp:x' yp:y'")
stereoN_to_S = stereoN.transition_map(stereoS, (x/(x^2+y^2), y/(x^2+y^2)),
intersection_name='W',
restrictions1= x^2+y^2!=0,
restrictions2= xp^2+xp^2!=0)
stereoS_to_N = stereoN_to_S.inverse()
W = U.intersection(V)
eU = stereoN.frame()
eV = stereoS.frame()
S2.frames()
The standard spherical (or polar) coordinates $(\theta,\phi)$ are defined on the open domain $A\subset W \subset \mathbb{S}^2$ that is the complement of the "origin meridian"; since the latter is the half-circle defined by $y=0$ and $x\geq 0$, we declare:
A = W.open_subset('A', coord_def={stereoN.restrict(W): (y!=0, x<0),
stereoS.restrict(W): (yp!=0, xp<0)})
spher.<th,ph> = A.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
spher_to_stereoN = spher.transition_map(stereoN.restrict(A),
(sin(th)*cos(ph)/(1-cos(th)),
sin(th)*sin(ph)/(1-cos(th))) )
spher_to_stereoN.set_inverse(2*atan(1/sqrt(x^2+y^2)), atan2(-y,-x)+pi)
spher_to_stereoN.display()
Let us first declare $\mathbb{R}^3$ as a 3-dimensional manifold covered by a single chart (the so-called Cartesian coordinates):
R3 = Manifold(3, 'R^3', r'\mathbb{R}^3', start_index=1)
cart.<X,Y,Z> = R3.chart() ; cart
The embedding of the sphere is defined as a differential mapping $\Phi: \mathbb{S}^2 \rightarrow \mathbb{R}^3$:
Phi = S2.diff_map(R3, {(stereoN, cart): [2*x/(1+x^2+y^2), 2*y/(1+x^2+y^2),
(x^2+y^2-1)/(1+x^2+y^2)],
(stereoS, cart): [2*xp/(1+xp^2+yp^2), 2*yp/(1+xp^2+yp^2),
(1-xp^2-yp^2)/(1+xp^2+yp^2)]},
name='Phi', latex_name=r'\Phi')
Phi.expr(stereoN.restrict(A), cart)
Phi.display(spher, cart)
Let us use $\Phi$ to draw the grid of spherical coordinates $(\theta,\phi)$ in terms of the Cartesian coordinates $(X,Y,Z)$ of $\mathbb{R}^3$:
graph_spher = spher.plot(chart=cart, mapping=Phi, nb_values=11, color='blue')
graph_spher
show(graph_spher, viewer='tachyon')
v = S2.vector_field(name='v')
v[eU,:] = [1, -2]
v.display(eU)
v.add_comp_by_continuation(eV, W, chart=stereoS)
v.display(eV)
A 3D view of the vector field $v$ is obtained via the embedding $\Phi$:
graph_v = v.plot(chart=cart, mapping=Phi, chart_domain=spher, nb_values=11, scale=0.2)
graph_v
show(graph_v, viewer='tachyon')
Let us superpose the plot of the spherical coordinate grid:
graph = graph_spher + graph_v
type(graph)
graph
If we permute graph_v
and graph_spher
in the graphic sum, we get an error:
graph = graph_v + graph_spher
type(graph)
graph
--------------------------------------------------------------------------- error Traceback (most recent call last) <ipython-input-18-cad80f3b6f4e> in <module>() ----> 1 graph /home/eric/sage/beta1/local/lib/python2.7/site-packages/IPython/core/displayhook.pyc in __call__(self, result) 244 self.start_displayhook() 245 self.write_output_prompt() --> 246 format_dict, md_dict = self.compute_format_data(result) 247 self.update_user_ns(result) 248 self.fill_exec_result(result) /home/eric/sage/beta1/local/lib/python2.7/site-packages/IPython/core/displayhook.pyc in compute_format_data(self, result) 148 149 """ --> 150 return self.shell.display_formatter.format(result) 151 152 # This can be set to True by the write_output_prompt method in a subclass /home/eric/sage/beta1/local/lib/python2.7/site-packages/sage/repl/display/formatter.pyc in format(self, obj, include, exclude) 148 # First, use Sage rich output if there is any 149 PLAIN_TEXT = u'text/plain' --> 150 sage_format, sage_metadata = self.dm.displayhook(obj) 151 assert PLAIN_TEXT in sage_format, 'plain text is always present' 152 if sage_format.keys() != [PLAIN_TEXT]: /home/eric/sage/beta1/local/lib/python2.7/site-packages/sage/repl/rich_output/display_manager.pyc in displayhook(self, obj) 764 self._backend.set_underscore_variable(obj) 765 plain_text, rich_output = self._rich_output_formatter(obj, dict()) --> 766 return self._backend.displayhook(plain_text, rich_output) 767 768 def display_immediately(self, obj, **rich_repr_kwds): /home/eric/sage/beta1/local/lib/python2.7/site-packages/sage/repl/rich_output/backend_ipython.pyc in displayhook(self, plain_text, rich_output) 525 from sage.repl.display.jsmol_iframe import JSMolHtml 526 jsmol = JSMolHtml(rich_output, height=500) --> 527 return ({u'text/html': jsmol.iframe(), 528 u'text/plain': plain_text.text.get_unicode(), 529 }, {}) /home/eric/sage/beta1/local/lib/python2.7/site-packages/sage/repl/display/jsmol_iframe.pyc in iframe(self) 259 </iframe> 260 """ --> 261 escaped_inner_html = self.inner_html().replace('"', '"') 262 iframe = IFRAME_TEMPLATE.format( 263 script=self.js_script(), /home/eric/sage/beta1/local/lib/python2.7/site-packages/sage/repl/display/jsmol_iframe.pyc in inner_html(self) 235 """ 236 return INNER_HTML_TEMPLATE.format( --> 237 script=self.js_script(), 238 width=self._width, 239 height=self._height, /home/eric/sage/beta1/local/lib/python2.7/site-packages/sage/repl/display/jsmol_iframe.pyc in js_script(self) 193 """ 194 script = [r"["] --> 195 for line in self.script().splitlines(): 196 script += [r" '{0}',".format(line)] 197 script += [r"].join('\n');"] /home/eric/sage/beta1/src/sage/misc/cachefunc.pyx in sage.misc.cachefunc.CachedMethodCallerNoArgs.__call__ (/home/eric/sage/beta1/src/build/cythonized/sage/misc/cachefunc.c:12716)() 2399 if self.cache is None: 2400 f = self.f -> 2401 self.cache = f(self._instance) 2402 return self.cache 2403 /home/eric/sage/beta1/local/lib/python2.7/site-packages/sage/repl/display/jsmol_iframe.pyc in script(self) 152 script = [] 153 with self._zip.open('SCRIPT') as SCRIPT: --> 154 for line in SCRIPT: 155 if line.startswith('pmesh'): 156 command, obj, meshfile = line.split(' ', 3) /home/eric/sage/beta1/local/lib/python/zipfile.pyc in readline(self, limit) 568 569 if not self._universal: --> 570 return io.BufferedIOBase.readline(self, limit) 571 572 line = '' /home/eric/sage/beta1/local/lib/python/zipfile.pyc in peek(self, n) 606 """Returns buffered bytes without advancing the position.""" 607 if n > len(self._readbuffer) - self._offset: --> 608 chunk = self.read(n) 609 if len(chunk) > self._offset: 610 self._readbuffer = chunk + self._readbuffer[self._offset:] /home/eric/sage/beta1/local/lib/python/zipfile.pyc in read(self, n) 630 data = self.read1(n) 631 elif n > len(buf): --> 632 data = self.read1(n - len(buf)) 633 else: 634 return buf /home/eric/sage/beta1/local/lib/python/zipfile.pyc in read1(self, n) 682 data = self._decompressor.decompress( 683 self._unconsumed, --> 684 max(n - len_readbuffer, self.MIN_READ_SIZE) 685 ) 686 error: Error -3 while decompressing: invalid distance too far back
The display with tachyon viewer is fine:
show(graph, viewer='tachyon')