def set_axes_labels(graph, xlabel, ylabel, zlabel, **kwds): r""" Set axes labels for a 3D graphics object ``graph``. This is a workaround for the lack of axes labels in 3D plots. This sets the labels as :func:`~sage.plot.plot3d.shapes2.text3d` objects at locations determined from the bounding box of the graphic object ``graph``. INPUT: - ``graph`` -- :class:`~sage.plot.plot3d.base.Graphics3d`; a 3D graphic object - ``xlabel`` -- string for the x-axis label - ``ylabel`` -- string for the y-axis label - ``zlabel`` -- string for the z-axis label - ``**kwds`` -- options (e.g. color) for text3d OUTPUT: - the 3D graphic object with text3d labels added EXAMPLES:: sage: g = sphere() sage: g.all [Graphics3d Object] sage: from sage.manifolds.utilities import set_axes_labels sage: ga = set_axes_labels(g, 'X', 'Y', 'Z', color='red') sage: ga.all # the 3D frame has now axes labels [Graphics3d Object, Graphics3d Object, Graphics3d Object, Graphics3d Object] """ from sage.plot.plot3d.shapes2 import text3d xmin, ymin, zmin = graph.bounding_box()[0] xmax, ymax, zmax = graph.bounding_box()[1] dx = xmax - xmin dy = ymax - ymin dz = zmax - zmin x1 = xmin + dx / 2 y1 = ymin + dy / 2 z1 = zmin + dz / 2 xmin1 = xmin - dx / 20 xmax1 = xmax + dx / 20 ymin1 = ymin - dy / 20 zmin1 = zmin - dz / 20 graph += text3d(' ' + xlabel, (x1, ymin1, zmin1), **kwds) graph += text3d(' ' + ylabel, (xmax1, y1, zmin1), **kwds) graph += text3d(' ' + zlabel, (xmin1, ymin1, z1), **kwds) return graph
def set_axes_labels(graph, xlabel, ylabel, zlabel, **kwds): r""" Set axes labels for a 3D graphics object ``graph``. This is a workaround for the lack of axes labels in 3D plots. This sets the labels as :func:`~sage.plot.plot3d.shapes2.text3d` objects at locations determined from the bounding box of the graphic object ``graph``. INPUT: - ``graph`` -- :class:`~sage.plot.plot3d.base.Graphics3d`; a 3D graphic object - ``xlabel`` -- string for the x-axis label - ``ylabel`` -- string for the y-axis label - ``zlabel`` -- string for the z-axis label - ``**kwds`` -- options (e.g. color) for text3d OUTPUT: - the 3D graphic object with text3d labels added EXAMPLES:: sage: g = sphere() sage: g.all [Graphics3d Object] sage: from sage.manifolds.utilities import set_axes_labels sage: ga = set_axes_labels(g, 'X', 'Y', 'Z', color='red') sage: ga.all # the 3D frame has now axes labels [Graphics3d Object, Graphics3d Object, Graphics3d Object, Graphics3d Object] """ from sage.plot.plot3d.shapes2 import text3d xmin, ymin, zmin = graph.bounding_box()[0] xmax, ymax, zmax = graph.bounding_box()[1] dx = xmax - xmin dy = ymax - ymin dz = zmax - zmin x1 = xmin + dx / 2 y1 = ymin + dy / 2 z1 = zmin + dz / 2 xmin1 = xmin - dx / 20 xmax1 = xmax + dx / 20 ymin1 = ymin - dy / 20 zmin1 = zmin - dz / 20 graph += text3d(' ' + xlabel, (x1, ymin1, zmin1), **kwds) graph += text3d(' ' + ylabel, (xmax1, y1, zmin1), **kwds) graph += text3d(' ' + zlabel, (xmin1, ymin1, z1), **kwds) return graph
def set_axes_labels(graph, xlabel, ylabel, zlabel, **kwds): r""" Set axes labels for a 3D graphics object. This is a workaround for the lack of axes labels in Sage 3D plots; it sets the labels as text3d objects at locations determined from the bounding box of the graphic object ``graph``. INPUT: - ``graph`` -- a 3D graphic object, as an instance of :class:`~sage.plot.plot3d.base.Graphics3d` - ``xlabel`` -- string for the x-axis label - ``ylabel`` -- string for the y-axis label - ``zlabel`` -- string for the z-axis label - ``**kwds`` -- options (e.g. color) for text3d OUTPUT: - the 3D graphic object with text3d labels added. """ from sage.plot.plot3d.shapes2 import text3d xmin, ymin, zmin = graph.bounding_box()[0] xmax, ymax, zmax = graph.bounding_box()[1] dx = xmax - xmin dy = ymax - ymin dz = zmax - zmin x1 = xmin + dx / 2 y1 = ymin + dy / 2 z1 = zmin + dz / 2 xmin1 = xmin - dx / 20 xmax1 = xmax + dx / 20 ymin1 = ymin - dy / 20 zmin1 = zmin - dz / 20 graph += text3d(' ' + xlabel, (x1, ymin1, zmin1), **kwds) graph += text3d(' ' + ylabel, (xmax1, y1, zmin1), **kwds) graph += text3d(' ' + zlabel, (xmin1, ymin1, z1), **kwds) return graph
def set_axes_labels(graph, xlabel, ylabel, zlabel, **kwds): r""" Set axes labels for a 3D graphics object. This is a workaround for the lack of axes labels in Sage 3D plots; it sets the labels as text3d objects at locations determined from the bounding box of the graphic object ``graph``. INPUT: - ``graph`` -- a 3D graphic object, as an instance of :class:`~sage.plot.plot3d.base.Graphics3d` - ``xlabel`` -- string for the x-axis label - ``ylabel`` -- string for the y-axis label - ``zlabel`` -- string for the z-axis label - ``**kwds`` -- options (e.g. color) for text3d OUTPUT: - the 3D graphic object with text3d labels added. """ from sage.plot.plot3d.shapes2 import text3d xmin, ymin, zmin = graph.bounding_box()[0] xmax, ymax, zmax = graph.bounding_box()[1] dx = xmax - xmin dy = ymax - ymin dz = zmax - zmin x1 = xmin + dx / 2 y1 = ymin + dy / 2 z1 = zmin + dz / 2 xmin1 = xmin - dx / 20 xmax1 = xmax + dx / 20 ymin1 = ymin - dy / 20 zmin1 = zmin - dz / 20 graph += text3d(' ' + xlabel, (x1, ymin1, zmin1), **kwds) graph += text3d(' ' + ylabel, (xmax1, y1, zmin1), **kwds) graph += text3d(' ' + zlabel, (xmin1, ymin1, z1), **kwds) return graph
def text(self, label, position): r""" Return text widget with label ``label`` at position ``position`` INPUT: - ``label`` -- a string, or a Sage object upon which latex will be called - ``position`` -- a position EXAMPLES:: sage: L = RootSystem(["A",2]).root_lattice() sage: options = L.plot_parse_options() sage: list(options.text("coucou", [0,1])) [Text 'coucou' at the point (0.0,1.0)] sage: list(options.text(L.simple_root(1), [0,1])) [Text '$\alpha_{1}$' at the point (0.0,1.0)] sage: options = RootSystem(["A",2]).root_lattice().plot_parse_options(labels=False) sage: options.text("coucou", [0,1]) 0 sage: options = RootSystem(["B",3]).root_lattice().plot_parse_options() sage: print options.text("coucou", [0,1,2]).x3d_str() <Transform translation='0 1 2'> <Shape><Text string='coucou' solid='true'/><Appearance><Material diffuseColor='0.0 0.0 0.0' shininess='1' specularColor='0.0 0.0 0.0'/></Appearance></Shape> <BLANKLINE> </Transform> """ if self.labels: if self.dimension <= 2: if not isinstance(label, basestring): label = "$" + str(latex(label)) + "$" from sage.plot.text import text return text(label, position, fontsize=15) elif self.dimension == 3: # LaTeX labels not yet supported in 3D if isinstance(label, basestring): label = label.replace("{", "").replace("}", "").replace("$", "").replace("_", "") else: label = str(label) from sage.plot.plot3d.shapes2 import text3d return text3d(label, position) else: raise NotImplementedError("Plots in dimension > 3") else: return self.empty()
def text(self, label, position): r""" Return text widget with label ``label`` at position ``position`` INPUT: - ``label`` -- a string, or a Sage object upon which latex will be called - ``position`` -- a position EXAMPLES:: sage: L = RootSystem(["A",2]).root_lattice() sage: options = L.plot_parse_options() sage: list(options.text("coucou", [0,1])) [Text 'coucou' at the point (0.0,1.0)] sage: list(options.text(L.simple_root(1), [0,1])) [Text '$\alpha_{1}$' at the point (0.0,1.0)] sage: options = RootSystem(["A",2]).root_lattice().plot_parse_options(labels=False) sage: options.text("coucou", [0,1]) 0 sage: options = RootSystem(["B",3]).root_lattice().plot_parse_options() sage: print options.text("coucou", [0,1,2]).x3d_str() <Transform translation='0 1 2'> <Shape><Text string='coucou' solid='true'/><Appearance><Material diffuseColor='0.0 0.0 0.0' shininess='1' specularColor='0.0 0.0 0.0'/></Appearance></Shape> <BLANKLINE> </Transform> """ if self.labels: if self.dimension <= 2: if not isinstance(label, basestring): label = "$" + str(latex(label)) + "$" from sage.plot.text import text return text(label, position, fontsize=15) elif self.dimension == 3: # LaTeX labels not yet supported in 3D if isinstance(label, basestring): label = label.replace("{", "").replace("}", "").replace( "$", "").replace("_", "") else: label = str(label) from sage.plot.plot3d.shapes2 import text3d return text3d(label, position) else: raise NotImplementedError("Plots in dimension > 3") else: return self.empty()
def plot3d(self, **kwds): """ Plots 2D text in 3D. EXAMPLES:: sage: T = text("ABC",(1,1)) sage: t = T[0] sage: s=t.plot3d() sage: s.jmol_repr(s.testing_render_params())[0][2] 'label "ABC"' sage: s._trans (1.0, 1.0, 0) """ from sage.plot.plot3d.shapes2 import text3d options = self._plot3d_options() options.update(kwds) return text3d(self.string, (self.x, self.y, 0), **options)
def plot3d(self, **kwds): """ Plots 2D text in 3D. EXAMPLES:: sage: T = text("ABC",(1,1)) sage: t = T[0] sage: s=t.plot3d() sage: s.jmol_repr(s.testing_render_params())[0][2] 'label "ABC"' sage: s._trans (1.0, 1.0, 0) """ from sage.plot.plot3d.shapes2 import text3d options = self._plot3d_options() options.update(kwds) return text3d(self.string, (self.x, self.y, 0), **options)
def show_pentaminos(box=(5, 8, 2)): r""" Show the 17 3-D pentaminos included in the game and the `5 \times 8 \times 2` box where 16 of them must fit. INPUT: - ``box`` - tuple of size three (optional, default: ``(5,8,2)``), size of the box OUTPUT: 3D Graphic object EXAMPLES:: sage: from sage.games.quantumino import show_pentaminos sage: show_pentaminos() # not tested (1s) To remove the frame do:: sage: show_pentaminos().show(frame=False) # not tested (1s) """ G = Graphics() for i, p in enumerate(pentaminos): x = 4 * (i % 4) y = 4 * (i / 4) q = p + (x, y, 0) G += q.show3d() G += text3d(str(i), (x, y, 2)) G += cube(color='gray', opacity=0.5).scale(box).translate((17, 6, 0)) # hack to set the aspect ratio to 1 a, b = G.bounding_box() a, b = map(vector, (a, b)) G.frame_aspect_ratio(tuple(b - a)) return G
def show_pentaminos(box=(5,8,2)): r""" Show the 17 3-D pentaminos included in the game and the `5 \times 8 \times 2` box where 16 of them must fit. INPUT: - ``box`` -- tuple of size three (optional, default: ``(5,8,2)``), size of the box OUTPUT: 3D Graphic object EXAMPLES:: sage: from sage.games.quantumino import show_pentaminos sage: show_pentaminos() # not tested (1s) To remove the frame do:: sage: show_pentaminos().show(frame=False) # not tested (1s) """ G = Graphics() for i, p in enumerate(pentaminos): x = 4 * (i % 4) y = 4 * (i // 4) q = p + (x, y, 0) G += q.show3d() G += text3d(str(i), (x, y, 2)) G += cube(color='gray',opacity=0.5).scale(box).translate((17, 6, 0)) # hack to set the aspect ratio to 1 a, b = G.bounding_box() a, b = map(vector, (a, b)) G.frame_aspect_ratio(tuple(b - a)) return G
def plot(self, chart=None, ambient_coords=None, mapping=None, label=None, parameters=None, **kwds): r""" For real manifolds, plot ``self`` in a Cartesian graph based on the coordinates of some ambient chart. The point is drawn in terms of two (2D graphics) or three (3D graphics) coordinates of a given chart, called hereafter the *ambient chart*. The domain of the ambient chart must contain the point, or its image by a continuous manifold map `\Phi`. INPUT: - ``chart`` -- (default: ``None``) the ambient chart (see above); if ``None``, the ambient chart is set the default chart of ``self.parent()`` - ``ambient_coords`` -- (default: ``None``) tuple containing the 2 or 3 coordinates of the ambient chart in terms of which the plot is performed; if ``None``, all the coordinates of the ambient chart are considered - ``mapping`` -- (default: ``None``) :class:`~sage.manifolds.continuous_map.ContinuousMap`; continuous manifold map `\Phi` providing the link between the current point `p` and the ambient chart ``chart``: the domain of ``chart`` must contain `\Phi(p)`; if ``None``, the identity map is assumed - ``label`` -- (default: ``None``) label printed next to the point; if ``None``, the point's name is used - ``parameters`` -- (default: ``None``) dictionary giving the numerical values of the parameters that may appear in the point coordinates - ``size`` -- (default: 10) size of the point once drawn as a small disk or sphere - ``color`` -- (default: ``'black'``) color of the point - ``label_color`` -- (default: ``None``) color to print the label; if ``None``, the value of ``color`` is used - ``fontsize`` -- (default: 10) size of the font used to print the label - ``label_offset`` -- (default: 0.1) determines the separation between the point and its label OUTPUT: - a graphic object, either an instance of :class:`~sage.plot.graphics.Graphics` for a 2D plot (i.e. based on 2 coordinates of the ambient chart) or an instance of :class:`~sage.plot.plot3d.base.Graphics3d` for a 3D plot (i.e. based on 3 coordinates of the ambient chart) EXAMPLES: Drawing a point on a 2-dimensional manifold:: sage: M = Manifold(2, 'M', structure='topological') sage: X.<x,y> = M.chart() sage: p = M.point((1,3), name='p') sage: g = p.plot(X) sage: print(g) Graphics object consisting of 2 graphics primitives sage: gX = X.plot(max_range=4) # plot of the coordinate grid sage: g + gX # display of the point atop the coordinate grid Graphics object consisting of 20 graphics primitives .. PLOT:: M = Manifold(2, 'M', structure='topological') X = M.chart('x y'); x,y = X[:] p = M.point((1,3), name='p') g = p.plot(X) gX = X.plot(max_range=4) sphinx_plot(g+gX) Actually, since ``X`` is the default chart of the open set in which ``p`` has been defined, it can be skipped in the arguments of ``plot``:: sage: g = p.plot() sage: g + gX Graphics object consisting of 20 graphics primitives Call with some options:: sage: g = p.plot(chart=X, size=40, color='green', label='$P$', ....: label_color='blue', fontsize=20, label_offset=0.3) sage: g + gX Graphics object consisting of 20 graphics primitives .. PLOT:: M = Manifold(2, 'M', structure='topological') X = M.chart('x y'); x,y = X[:] p = M.point((1,3), name='p') g = p.plot(chart=X, size=40, color='green', label='$P$', \ label_color='blue', fontsize=20, label_offset=0.3) gX = X.plot(max_range=4) sphinx_plot(g+gX) Use of the ``parameters`` option to set a numerical value of some symbolic variable:: sage: a = var('a') sage: q = M.point((a,2*a), name='q') sage: gq = q.plot(parameters={a:-2}, label_offset=0.2) sage: g + gX + gq Graphics object consisting of 22 graphics primitives .. PLOT:: M = Manifold(2, 'M', structure='topological') X = M.chart('x y'); x,y = X[:] p = M.point((1,3), name='p') g = p.plot(chart=X, size=40, color='green', label='$P$', \ label_color='blue', fontsize=20, label_offset=0.3) var('a') q = M.point((a,2*a), name='q') gq = q.plot(parameters={a:-2}, label_offset=0.2) gX = X.plot(max_range=4) sphinx_plot(g+gX+gq) The numerical value is used only for the plot:: sage: q.coord() (a, 2*a) Drawing a point on a 3-dimensional manifold:: sage: M = Manifold(3, 'M', structure='topological') sage: X.<x,y,z> = M.chart() sage: p = M.point((2,1,3), name='p') sage: g = p.plot() sage: print(g) Graphics3d Object sage: gX = X.plot(nb_values=5) # coordinate mesh cube sage: g + gX # display of the point atop the coordinate mesh Graphics3d Object Call with some options:: sage: g = p.plot(chart=X, size=40, color='green', label='P_1', ....: label_color='blue', fontsize=20, label_offset=0.3) sage: g + gX Graphics3d Object An example of plot via a mapping: plot of a point on a 2-sphere viewed in the 3-dimensional space ``M``:: sage: S2 = Manifold(2, 'S^2', structure='topological') sage: U = S2.open_subset('U') # the open set covered by spherical coord. sage: XS.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi') sage: p = U.point((pi/4, pi/8), name='p') sage: F = S2.continuous_map(M, {(XS, X): [sin(th)*cos(ph), ....: sin(th)*sin(ph), cos(th)]}, name='F') sage: F.display() F: S^2 --> M on U: (th, ph) |--> (x, y, z) = (cos(ph)*sin(th), sin(ph)*sin(th), cos(th)) sage: g = p.plot(chart=X, mapping=F) sage: gS2 = XS.plot(chart=X, mapping=F, nb_values=9) sage: g + gS2 Graphics3d Object Use of the option ``ambient_coords`` for plots on a 4-dimensional manifold:: sage: M = Manifold(4, 'M', structure='topological') sage: X.<t,x,y,z> = M.chart() sage: p = M.point((1,2,3,4), name='p') sage: g = p.plot(X, ambient_coords=(t,x,y), label_offset=0.4) # the coordinate z is skipped sage: gX = X.plot(X, ambient_coords=(t,x,y), nb_values=5) # long time sage: g + gX # 3D plot # long time Graphics3d Object sage: g = p.plot(X, ambient_coords=(t,y,z), label_offset=0.4) # the coordinate x is skipped sage: gX = X.plot(X, ambient_coords=(t,y,z), nb_values=5) # long time sage: g + gX # 3D plot # long time Graphics3d Object sage: g = p.plot(X, ambient_coords=(y,z), label_offset=0.4) # the coordinates t and x are skipped sage: gX = X.plot(X, ambient_coords=(y,z)) sage: g + gX # 2D plot Graphics object consisting of 20 graphics primitives .. PLOT:: M = Manifold(4, 'M', structure='topological') X = M.chart('t x y z'); t,x,y,z = X[:] p = M.point((1,2,3,4), name='p') g = p.plot(X, ambient_coords=(y,z), label_offset=0.4) gX = X.plot(X, ambient_coords=(y,z)) sphinx_plot(g+gX) """ from sage.plot.point import point2d from sage.plot.text import text from sage.plot.graphics import Graphics from sage.plot.plot3d.shapes2 import point3d, text3d from sage.manifolds.chart import Chart if self._manifold.base_field_type() != "real": raise NotImplementedError( "plot of points on manifolds over fields different" " from the real field is not implemented" ) # The ambient chart: if chart is None: chart = self.parent().default_chart() elif not isinstance(chart, Chart): raise TypeError("the argument 'chart' must be a coordinate chart") # The effective point to be plotted: if mapping is None: eff_point = self else: eff_point = mapping(self) # The coordinates of the ambient chart used for the plot: if ambient_coords is None: ambient_coords = chart[:] elif not isinstance(ambient_coords, tuple): ambient_coords = tuple(ambient_coords) nca = len(ambient_coords) if nca != 2 and nca != 3: raise TypeError("invalid number of ambient coordinates: {}".format(nca)) # Extract the kwds options size = kwds["size"] color = kwds["color"] label_color = kwds["label_color"] fontsize = kwds["fontsize"] label_offset = kwds["label_offset"] # The point coordinates: coords = eff_point.coord(chart) xx = chart[:] xp = [coords[xx.index(c)] for c in ambient_coords] if parameters is not None: xps = [coord.substitute(parameters) for coord in xp] xp = xps xlab = [coord + label_offset for coord in xp] if label_color is None: label_color = color resu = Graphics() if nca == 2: if label is None: label = r"$" + self._latex_name + r"$" resu += point2d(xp, color=color, size=size) + text(label, xlab, fontsize=fontsize, color=label_color) else: if label is None: label = self._name resu += point3d(xp, color=color, size=size) + text3d(label, xlab, fontsize=fontsize, color=label_color) return resu
def plot(self, chart=None, ambient_coords=None, mapping=None, size=10, color='black', label=None, label_color=None, fontsize=10, label_offset=0.1, parameters=None): r""" Plot the current point (``self``) in a Cartesian graph based on the coordinates of some ambient chart. The point is drawn in terms of two (2D graphics) or three (3D graphics) coordinates of a given chart, called hereafter the *ambient chart*. The domain of the ambient chart must contain the point, or its image by a differentiable mapping `\Phi`. INPUT: - ``chart`` -- (default: ``None``) the ambient chart (see above); if ``None``, the ambient chart is set the default chart of ``self.containing_set()`` - ``ambient_coords`` -- (default: ``None``) tuple containing the 2 or 3 coordinates of the ambient chart in terms of which the plot is performed; if ``None``, all the coordinates of the ambient chart are considered - ``mapping`` -- (default: ``None``) differentiable mapping `\Phi` (instance of :class:`~sage.geometry.manifolds.diffmapping.DiffMapping`) providing the link between the point `p` represented by ``self`` and the ambient chart ``chart``: the domain of ``chart`` must contain `\Phi(p)`; if ``None``, the identity mapping is assumed - ``size`` -- (default: 10) size of the point once drawn as a small disk or sphere - ``color`` -- (default: 'black') color of the point - ``label`` -- (default: ``None``) label printed next to the point; if ``None``, the point's name is used. - ``label_color`` -- (default: ``None``) color to print the label; if ``None``, the value of ``color`` is used - ``fontsize`` -- (default: 10) size of the font used to print the label - ``label_offset`` -- (default: 0.1) determines the separation between the point and its label - ``parameters`` -- (default: ``None``) dictionary giving the numerical values of the parameters that may appear in the point coordinates OUTPUT: - a graphic object, either an instance of :class:`~sage.plot.graphics.Graphics` for a 2D plot (i.e. based on 2 coordinates of the ambient chart) or an instance of :class:`~sage.plot.plot3d.base.Graphics3d` for a 3D plot (i.e. based on 3 coordinates of the ambient chart) EXAMPLES: Drawing a point on a 2-dimensional manifold:: sage: M = Manifold(2, 'M') sage: X.<x,y> = M.chart() sage: p = M.point((1,3), name='p') sage: g = p.plot(X) sage: print g Graphics object consisting of 2 graphics primitives sage: gX = X.plot() # plot of the coordinate grid sage: show(g+gX) # display of the point atop the coordinate grid Actually, since ``X`` is the default chart of the open set in which ``p`` has been defined, it can be skipped in the arguments of ``plot``:: sage: g = p.plot() sage: show(g+gX) Call with some options:: sage: g = p.plot(chart=X, size=40, color='green', label='$P$', ....: label_color='blue', fontsize=20, label_offset=0.3) sage: show(g+gX) Use of the ``parameters`` option to set a numerical value of some symbolic variable:: sage: a = var('a') sage: q = M.point((a,2*a), name='q') sage: gq = q.plot(parameters={a:-2}) sage: show(g+gX+gq) The numerical value is used only for the plot:: sage: q.coord() (a, 2*a) Drawing a point on a 3-dimensional manifold:: sage: M = Manifold(3, 'M') sage: X.<x,y,z> = M.chart() sage: p = M.point((2,1,3), name='p') sage: g = p.plot() sage: print g Graphics3d Object sage: gX = X.plot(nb_values=5) # coordinate mesh cube sage: show(g+gX) # display of the point atop the coordinate mesh Call with some options:: sage: g = p.plot(chart=X, size=40, color='green', label='P_1', ....: label_color='blue', fontsize=20, label_offset=0.3) sage: show(g+gX) An example of plot via a differential mapping: plot of a point on a 2-sphere viewed in the 3-dimensional space ``M``:: sage: S2 = Manifold(2, 'S^2') sage: U = S2.open_subset('U') # the open set covered by spherical coord. sage: XS.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi') sage: p = U.point((pi/4, pi/8), name='p') sage: F = S2.diff_mapping(M, {(XS, X): [sin(th)*cos(ph), ....: sin(th)*sin(ph), cos(th)]}, name='F') sage: F.display() F: S^2 --> M on U: (th, ph) |--> (x, y, z) = (cos(ph)*sin(th), sin(ph)*sin(th), cos(th)) sage: g = p.plot(chart=X, mapping=F) sage: gS2 = XS.plot(chart=X, mapping=F, nb_values=9) sage: show(g+gS2) Use of the option ``ambient_coords`` for plots on a 4-dimensional manifold:: sage: M = Manifold(4, 'M') sage: X.<t,x,y,z> = M.chart() sage: p = M.point((1,2,3,4), name='p') sage: g = p.plot(X, ambient_coords=(t,x,y)) # the coordinate z is skipped sage: gX = X.plot(X, ambient_coords=(t,x,y), nb_values=5) sage: show(g+gX) # 3D plot sage: g = p.plot(X, ambient_coords=(t,y,z)) # the coordinate x is skipped sage: gX = X.plot(X, ambient_coords=(t,y,z), nb_values=5) sage: show(g+gX) # 3D plot sage: g = p.plot(X, ambient_coords=(y,z)) # the coordinates t and x are skipped sage: gX = X.plot(X, ambient_coords=(y,z)) sage: show(g+gX) # 2D plot """ from sage.plot.point import point2d from sage.plot.text import text from sage.plot.graphics import Graphics from sage.plot.plot3d.shapes2 import point3d, text3d from sage.geometry.manifolds.chart import Chart # The ambient chart: if chart is None: chart = self.containing_set().default_chart() elif not isinstance(chart, Chart): raise TypeError("the argument 'chart' must be a coordinate chart") # The effective point to be plotted: if mapping is None: eff_point = self else: eff_point = mapping(self) # The coordinates of the ambient chart used for the plot: if ambient_coords is None: ambient_coords = chart._xx elif not isinstance(ambient_coords, tuple): ambient_coords = tuple(ambient_coords) nca = len(ambient_coords) if nca != 2 and nca !=3: raise TypeError("Bad number of ambient coordinates: " + str(nca)) # The point coordinates: coords = eff_point.coord(chart) xx = chart[:] xp = [coords[xx.index(c)] for c in ambient_coords] if parameters is not None: xps = [coord.substitute(parameters) for coord in xp] xp = xps xlab = [coord + label_offset for coord in xp] if label_color is None: label_color = color resu = Graphics() if nca == 2: if label is None: label = r'$' + self._latex_name + r'$' resu += point2d(xp, color=color, size=size) + \ text(label, xlab, fontsize=fontsize, color=label_color) else: if label is None: label = self._name resu += point3d(xp, color=color, size=size) + \ text3d(label, xlab, fontsize=fontsize, color=label_color) return resu
def plot(self, chart=None, ambient_coords=None, mapping=None, color='blue', print_label=True, label=None, label_color=None, fontsize=10, label_offset=0.1, parameters=None, **extra_options): r""" Plot the vector in a Cartesian graph based on the coordinates of some ambient chart. The vector is drawn in terms of two (2D graphics) or three (3D graphics) coordinates of a given chart, called hereafter the *ambient chart*. The vector's base point `p` (or its image `\Phi(p)` by some differentiable mapping `\Phi`) must lie in the ambient chart's domain. If `\Phi` is different from the identity mapping, the vector actually depicted is `\mathrm{d}\Phi_p(v)`, where `v` is the current vector (``self``) (see the example of a vector tangent to the 2-sphere below, where `\Phi: S^2 \to \RR^3`). INPUT: - ``chart`` -- (default: ``None``) the ambient chart (see above); if ``None``, it is set to the default chart of the open set containing the point at which the vector (or the vector image via the differential `\mathrm{d}\Phi_p` of ``mapping``) is defined - ``ambient_coords`` -- (default: ``None``) tuple containing the 2 or 3 coordinates of the ambient chart in terms of which the plot is performed; if ``None``, all the coordinates of the ambient chart are considered - ``mapping`` -- (default: ``None``) :class:`~sage.manifolds.differentiable.diff_map.DiffMap`; differentiable mapping `\Phi` providing the link between the point `p` at which the vector is defined and the ambient chart ``chart``: the domain of ``chart`` must contain `\Phi(p)`; if ``None``, the identity mapping is assumed - ``scale`` -- (default: 1) value by which the length of the arrow representing the vector is multiplied - ``color`` -- (default: 'blue') color of the arrow representing the vector - ``print_label`` -- (boolean; default: ``True``) determines whether a label is printed next to the arrow representing the vector - ``label`` -- (string; default: ``None``) label printed next to the arrow representing the vector; if ``None``, the vector's symbol is used, if any - ``label_color`` -- (default: ``None``) color to print the label; if ``None``, the value of ``color`` is used - ``fontsize`` -- (default: 10) size of the font used to print the label - ``label_offset`` -- (default: 0.1) determines the separation between the vector arrow and the label - ``parameters`` -- (default: ``None``) dictionary giving the numerical values of the parameters that may appear in the coordinate expression of ``self`` (see example below) - ``**extra_options`` -- extra options for the arrow plot, like ``linestyle``, ``width`` or ``arrowsize`` (see :func:`~sage.plot.arrow.arrow2d` and :func:`~sage.plot.plot3d.shapes.arrow3d` for details) OUTPUT: - a graphic object, either an instance of :class:`~sage.plot.graphics.Graphics` for a 2D plot (i.e. based on 2 coordinates of ``chart``) or an instance of :class:`~sage.plot.plot3d.base.Graphics3d` for a 3D plot (i.e. based on 3 coordinates of ``chart``) EXAMPLES: Vector tangent to a 2-dimensional manifold:: sage: M = Manifold(2, 'M') sage: X.<x,y> = M.chart() sage: p = M((2,2), name='p') sage: Tp = M.tangent_space(p) sage: v = Tp((2, 1), name='v') ; v Tangent vector v at Point p on the 2-dimensional differentiable manifold M Plot of the vector alone (arrow + label):: sage: v.plot() Graphics object consisting of 2 graphics primitives Plot atop of the chart grid:: sage: X.plot() + v.plot() Graphics object consisting of 20 graphics primitives .. PLOT:: M = Manifold(2, 'M') X = M.chart('x y'); x, y = X[:] p = M((2,2), name='p'); Tp = M.tangent_space(p) v = Tp((2, 1), name='v') g = X.plot() + v.plot() sphinx_plot(g) Plots with various options:: sage: X.plot() + v.plot(color='green', scale=2, label='V') Graphics object consisting of 20 graphics primitives .. PLOT:: M = Manifold(2, 'M') X = M.chart('x y'); x, y = X[:] p = M((2,2), name='p'); Tp = M.tangent_space(p) v = Tp((2, 1), name='v') g = X.plot() + v.plot(color='green', scale=2, label='V') sphinx_plot(g) :: sage: X.plot() + v.plot(print_label=False) Graphics object consisting of 19 graphics primitives .. PLOT:: M = Manifold(2, 'M') X = M.chart('x y'); x, y = X[:] p = M((2,2), name='p'); Tp = M.tangent_space(p) v = Tp((2, 1), name='v') g = X.plot() + v.plot(print_label=False) sphinx_plot(g) :: sage: X.plot() + v.plot(color='green', label_color='black', ....: fontsize=20, label_offset=0.2) Graphics object consisting of 20 graphics primitives .. PLOT:: M = Manifold(2, 'M') X = M.chart('x y'); x, y = X[:] p = M((2,2), name='p'); Tp = M.tangent_space(p) v = Tp((2, 1), name='v') g = X.plot() + v.plot(color='green', label_color='black', fontsize=20, label_offset=0.2) sphinx_plot(g) :: sage: X.plot() + v.plot(linestyle=':', width=4, arrowsize=8, ....: fontsize=20) Graphics object consisting of 20 graphics primitives .. PLOT:: M = Manifold(2, 'M') X = M.chart('x y'); x, y = X[:] p = M((2,2), name='p'); Tp = M.tangent_space(p) v = Tp((2, 1), name='v') g = X.plot() + v.plot(linestyle=':', width=4, arrowsize=8, fontsize=20) sphinx_plot(g) Plot with specific values of some free parameters:: sage: var('a b') (a, b) sage: v = Tp((1+a, -b^2), name='v') ; v.display() v = (a + 1) d/dx - b^2 d/dy sage: X.plot() + v.plot(parameters={a: -2, b: 3}) Graphics object consisting of 20 graphics primitives Special case of the zero vector:: sage: v = Tp.zero() ; v Tangent vector zero at Point p on the 2-dimensional differentiable manifold M sage: X.plot() + v.plot() Graphics object consisting of 19 graphics primitives Vector tangent to a 4-dimensional manifold:: sage: M = Manifold(4, 'M') sage: X.<t,x,y,z> = M.chart() sage: p = M((0,1,2,3), name='p') sage: Tp = M.tangent_space(p) sage: v = Tp((5,4,3,2), name='v') ; v Tangent vector v at Point p on the 4-dimensional differentiable manifold M We cannot make a 4D plot directly:: sage: v.plot() Traceback (most recent call last): ... ValueError: the number of coordinates involved in the plot must be either 2 or 3, not 4 Rather, we have to select some chart coordinates for the plot, via the argument ``ambient_coords``. For instance, for a 2-dimensional plot in terms of the coordinates `(x, y)`:: sage: v.plot(ambient_coords=(x,y)) Graphics object consisting of 2 graphics primitives .. PLOT:: M = Manifold(4, 'M') X = M.chart('t x y z'); t,x,y,z = X[:] p = M((0,1,2,3), name='p'); Tp = M.tangent_space(p) v = Tp((5,4,3,2), name='v') g = X.plot(ambient_coords=(x,y)) + v.plot(ambient_coords=(x,y)) sphinx_plot(g) This plot involves only the components `v^x` and `v^y` of `v`. Similarly, for a 3-dimensional plot in terms of the coordinates `(t, x, y)`:: sage: g = v.plot(ambient_coords=(t,x,z)) sage: print(g) Graphics3d Object This plot involves only the components `v^t`, `v^x` and `v^z` of `v`. A nice 3D view atop the coordinate grid is obtained via:: sage: (X.plot(ambient_coords=(t,x,z)) # long time ....: + v.plot(ambient_coords=(t,x,z), ....: label_offset=0.5, width=6)) Graphics3d Object .. PLOT:: M = Manifold(4, 'M') X = M.chart('t x y z'); t,x,y,z = X[:] p = M((0,1,2,3), name='p'); Tp = M.tangent_space(p) v = Tp((5,4,3,2), name='v') g = X.plot(ambient_coords=(t,x,z)) + v.plot(ambient_coords=(t,x,z), label_offset=0.5, width=6) sphinx_plot(g) An example of plot via a differential mapping: plot of a vector tangent to a 2-sphere viewed in `\RR^3`:: sage: S2 = Manifold(2, 'S^2') sage: U = S2.open_subset('U') # the open set covered by spherical coord. sage: XS.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi') sage: R3 = Manifold(3, 'R^3') sage: X3.<x,y,z> = R3.chart() sage: F = S2.diff_map(R3, {(XS, X3): [sin(th)*cos(ph), ....: sin(th)*sin(ph), ....: cos(th)]}, name='F') sage: F.display() # the standard embedding of S^2 into R^3 F: S^2 --> R^3 on U: (th, ph) |--> (x, y, z) = (cos(ph)*sin(th), sin(ph)*sin(th), cos(th)) sage: p = U.point((pi/4, 7*pi/4), name='p') sage: v = XS.frame()[1].at(p) ; v # the coordinate vector d/dphi at p Tangent vector d/dph at Point p on the 2-dimensional differentiable manifold S^2 sage: graph_v = v.plot(mapping=F) sage: graph_S2 = XS.plot(chart=X3, mapping=F, number_values=9) # long time sage: graph_v + graph_S2 # long time Graphics3d Object .. PLOT:: S2 = Manifold(2, 'S^2') U = S2.open_subset('U') XS = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi') th, ph = XS[:] R3 = Manifold(3, 'R^3') X3 = R3.chart('x y z') F = S2.diff_map(R3, {(XS, X3): [sin(th)*cos(ph), sin(th)*sin(ph), cos(th)]}, name='F') p = U.point((pi/4, 7*pi/4), name='p') v = XS.frame()[1].at(p) graph_v = v.plot(mapping=F) graph_S2 = XS.plot(chart=X3, mapping=F, number_values=9) sphinx_plot(graph_v + graph_S2) """ from sage.plot.arrow import arrow2d from sage.plot.text import text from sage.plot.graphics import Graphics from sage.plot.plot3d.shapes import arrow3d from sage.plot.plot3d.shapes2 import text3d from sage.misc.functional import numerical_approx from sage.manifolds.differentiable.chart import DiffChart scale = extra_options.pop("scale") # # The "effective" vector to be plotted # if mapping is None: eff_vector = self base_point = self._point else: #!# check # For efficiency, the method FiniteRankFreeModuleMorphism._call_() # is called instead of FiniteRankFreeModuleMorphism.__call__() eff_vector = mapping.differential(self._point)._call_(self) base_point = mapping(self._point) # # The chart w.r.t. which the vector is plotted # if chart is None: chart = base_point.parent().default_chart() elif not isinstance(chart, DiffChart): raise TypeError("{} is not a chart".format(chart)) # # Coordinates of the above chart w.r.t. which the vector is plotted # if ambient_coords is None: ambient_coords = chart[:] # all chart coordinates are used n_pc = len(ambient_coords) if n_pc != 2 and n_pc != 3: raise ValueError("the number of coordinates involved in the " + "plot must be either 2 or 3, not {}".format(n_pc)) # indices coordinates involved in the plot: ind_pc = [chart[:].index(pc) for pc in ambient_coords] # # Components of the vector w.r.t. the chart frame # basis = chart.frame().at(base_point) vcomp = eff_vector.comp(basis=basis)[:] xp = base_point.coord(chart=chart) # # The arrow # resu = Graphics() if parameters is None: coord_tail = [numerical_approx(xp[i]) for i in ind_pc] coord_head = [ numerical_approx(xp[i] + scale * vcomp[i]) for i in ind_pc ] else: coord_tail = [ numerical_approx(xp[i].substitute(parameters)) for i in ind_pc ] coord_head = [ numerical_approx( (xp[i] + scale * vcomp[i]).substitute(parameters)) for i in ind_pc ] if coord_head != coord_tail: if n_pc == 2: resu += arrow2d(tailpoint=coord_tail, headpoint=coord_head, color=color, **extra_options) else: resu += arrow3d(coord_tail, coord_head, color=color, **extra_options) # # The label # if print_label: if label is None: if n_pc == 2 and self._latex_name is not None: label = r'$' + self._latex_name + r'$' if n_pc == 3 and self._name is not None: label = self._name if label is not None: xlab = [xh + label_offset for xh in coord_head] if label_color is None: label_color = color if n_pc == 2: resu += text(label, xlab, fontsize=fontsize, color=label_color) else: resu += text3d(label, xlab, fontsize=fontsize, color=label_color) return resu
def plot_hyperplane(hyperplane, **kwds): r""" Return the plot of a single hyperplane. INPUT: - ``**kwds`` -- plot options: see below OUTPUT: A graphics object of the plot. .. RUBRIC:: Plot Options Beside the usual plot options (enter ``plot?``), the plot command for hyperplanes includes the following: - ``hyperplane_label`` -- Boolean value or string (default: ``True``). If ``True``, the hyperplane is labeled with its equation, if a string, it is labeled by that string, otherwise it is not labeled. - ``label_color`` -- (Default: ``'black'``) Color for hyperplane_label. - ``label_fontsize`` -- Size for ``hyperplane_label`` font (default: 14) (does not work in 3d, yet). - ``label_offset`` -- (Default: 0-dim: 0.1, 1-dim: (0,1), 2-dim: (0,0,0.2)) Amount by which label is offset from ``hyperplane.point()``. - ``point_size`` -- (Default: 50) Size of points in a zero-dimensional arrangement or of an arrangement over a finite field. - ``ranges`` -- Range for the parameters for the parametric plot of the hyperplane. If a single positive number ``r`` is given for the value of ``ranges``, then the ranges for all parameters are set to `[-r, r]`. Otherwise, for a line in the plane, ``ranges`` has the form ``[a, b]`` (default: [-3,3]), and for a plane in 3-space, the ``ranges`` has the form ``[[a, b], [c, d]]`` (default: [[-3,3],[-3,3]]). (The ranges are centered around ``hyperplane.point()``.) EXAMPLES:: sage: H1.<x> = HyperplaneArrangements(QQ) sage: a = 3*x + 4 sage: a.plot() # indirect doctest Graphics object consisting of 3 graphics primitives sage: a.plot(point_size=100,hyperplane_label='hello') Graphics object consisting of 3 graphics primitives sage: H2.<x,y> = HyperplaneArrangements(QQ) sage: b = 3*x + 4*y + 5 sage: b.plot() Graphics object consisting of 2 graphics primitives sage: b.plot(ranges=(1,5),label_offset=(2,-1)) Graphics object consisting of 2 graphics primitives sage: opts = {'hyperplane_label':True, 'label_color':'green', ....: 'label_fontsize':24, 'label_offset':(0,1.5)} sage: b.plot(**opts) Graphics object consisting of 2 graphics primitives sage: H3.<x,y,z> = HyperplaneArrangements(QQ) sage: c = 2*x + 3*y + 4*z + 5 sage: c.plot() Graphics3d Object sage: c.plot(label_offset=(1,0,1), color='green', label_color='red', frame=False) Graphics3d Object sage: d = -3*x + 2*y + 2*z + 3 sage: d.plot(opacity=0.8) Graphics3d Object sage: e = 4*x + 2*z + 3 sage: e.plot(ranges=[[-1,1],[0,8]], label_offset=(2,2,1), aspect_ratio=1) Graphics3d Object """ if hyperplane.base_ring().characteristic(): raise NotImplementedError('base field must have characteristic zero') elif hyperplane.dimension() not in [ 0, 1, 2 ]: # dimension of hyperplane, not ambient space raise ValueError('can only plot hyperplanes in dimensions 1, 2, 3') # handle extra keywords if 'hyperplane_label' in kwds: hyp_label = kwds.pop('hyperplane_label') if not hyp_label: has_hyp_label = False else: has_hyp_label = True else: # default hyp_label = True has_hyp_label = True if has_hyp_label: if hyp_label: # then label hyperplane with its equation if hyperplane.dimension() == 2: # jmol does not like latex label = hyperplane._repr_linear(include_zero=False) else: label = hyperplane._latex_() else: label = hyp_label # a string if 'label_color' in kwds: label_color = kwds.pop('label_color') else: label_color = 'black' if 'label_fontsize' in kwds: label_fontsize = kwds.pop('label_fontsize') else: label_fontsize = 14 if 'label_offset' in kwds: has_offset = True label_offset = kwds.pop('label_offset') else: has_offset = False # give default values below if 'point_size' in kwds: pt_size = kwds.pop('point_size') else: pt_size = 50 if 'ranges' in kwds: ranges_set = True ranges = kwds.pop('ranges') else: ranges_set = False # give default values below # the extra keywords have now been handled # now create the plot if hyperplane.dimension() == 0: # a point on a line x, = hyperplane.A() d = hyperplane.b() p = point((d / x, 0), size=pt_size, **kwds) if has_hyp_label: if not has_offset: label_offset = 0.1 p += text(label, (d / x, label_offset), color=label_color, fontsize=label_fontsize) p += text('', (d / x, label_offset + 0.4)) # add space at top if 'ymax' not in kwds: kwds['ymax'] = 0.5 elif hyperplane.dimension() == 1: # a line in the plane pnt = hyperplane.point() w = hyperplane.linear_part().matrix() t = SR.var('t') if ranges_set: if isinstance(ranges, (list, tuple)): t0, t1 = ranges else: # ranges should be a single positive number t0, t1 = -ranges, ranges else: # default t0, t1 = -3, 3 p = parametric_plot(pnt + t * w[0], (t, t0, t1), **kwds) if has_hyp_label: if has_offset: b0, b1 = label_offset else: b0, b1 = 0, 0.2 label = text(label, (pnt[0] + b0, pnt[1] + b1), color=label_color, fontsize=label_fontsize) p += label elif hyperplane.dimension() == 2: # a plane in 3-space pnt = hyperplane.point() w = hyperplane.linear_part().matrix() s, t = SR.var('s t') if ranges_set: if isinstance(ranges, (list, tuple)): s0, s1 = ranges[0] t0, t1 = ranges[1] else: # ranges should be a single positive integers s0, s1 = -ranges, ranges t0, t1 = -ranges, ranges else: # default s0, s1 = -3, 3 t0, t1 = -3, 3 p = parametric_plot3d(pnt + s * w[0] + t * w[1], (s, s0, s1), (t, t0, t1), **kwds) if has_hyp_label: if has_offset: b0, b1, b2 = label_offset else: b0, b1, b2 = 0, 0, 0 label = text3d(label, (pnt[0] + b0, pnt[1] + b1, pnt[2] + b2), color=label_color, fontsize=label_fontsize) p += label return p
def plot_hyperplane(hyperplane, **kwds): r""" Return the plot of a single hyperplane. INPUT: - ``**kwds`` -- plot options: see below OUTPUT: A graphics object of the plot. .. RUBRIC:: Plot Options Beside the usual plot options (enter ``plot?``), the plot command for hyperplanes includes the following: - ``hyperplane_label`` -- Boolean value or string (default: ``True``). If ``True``, the hyperplane is labeled with its equation, if a string, it is labeled by that string, otherwise it is not labeled. - ``label_color`` -- (Default: ``'black'``) Color for hyperplane_label. - ``label_fontsize`` -- Size for ``hyperplane_label`` font (default: 14) (does not work in 3d, yet). - ``label_offset`` -- (Default: 0-dim: 0.1, 1-dim: (0,1), 2-dim: (0,0,0.2)) Amount by which label is offset from ``hyperplane.point()``. - ``point_size`` -- (Default: 50) Size of points in a zero-dimensional arrangement or of an arrangement over a finite field. - ``ranges`` -- Range for the parameters for the parametric plot of the hyperplane. If a single positive number ``r`` is given for the value of ``ranges``, then the ranges for all parameters are set to `[-r, r]`. Otherwise, for a line in the plane, ``ranges`` has the form ``[a, b]`` (default: [-3,3]), and for a plane in 3-space, the ``ranges`` has the form ``[[a, b], [c, d]]`` (default: [[-3,3],[-3,3]]). (The ranges are centered around ``hyperplane.point()``.) EXAMPLES:: sage: H1.<x> = HyperplaneArrangements(QQ) sage: a = 3*x + 4 sage: a.plot() # indirect doctest Graphics object consisting of 3 graphics primitives sage: a.plot(point_size=100,hyperplane_label='hello') Graphics object consisting of 3 graphics primitives sage: H2.<x,y> = HyperplaneArrangements(QQ) sage: b = 3*x + 4*y + 5 sage: b.plot() Graphics object consisting of 2 graphics primitives sage: b.plot(ranges=(1,5),label_offset=(2,-1)) Graphics object consisting of 2 graphics primitives sage: opts = {'hyperplane_label':True, 'label_color':'green', ....: 'label_fontsize':24, 'label_offset':(0,1.5)} sage: b.plot(**opts) Graphics object consisting of 2 graphics primitives sage: H3.<x,y,z> = HyperplaneArrangements(QQ) sage: c = 2*x + 3*y + 4*z + 5 sage: c.plot() Graphics3d Object sage: c.plot(label_offset=(1,0,1), color='green', label_color='red', frame=False) Graphics3d Object sage: d = -3*x + 2*y + 2*z + 3 sage: d.plot(opacity=0.8) Graphics3d Object sage: e = 4*x + 2*z + 3 sage: e.plot(ranges=[[-1,1],[0,8]], label_offset=(2,2,1), aspect_ratio=1) Graphics3d Object """ if hyperplane.base_ring().characteristic() != 0: raise NotImplementedError('base field must have characteristic zero') elif hyperplane.dimension() not in [0, 1, 2]: # dimension of hyperplane, not ambient space raise ValueError('can only plot hyperplanes in dimensions 1, 2, 3') # handle extra keywords if 'hyperplane_label' in kwds: hyp_label = kwds.pop('hyperplane_label') if not hyp_label: has_hyp_label = False else: has_hyp_label = True else: # default hyp_label = True has_hyp_label = True if has_hyp_label: if hyp_label: # then label hyperplane with its equation if hyperplane.dimension() == 2: # jmol does not like latex label = hyperplane._repr_linear(include_zero=False) else: label = hyperplane._latex_() else: label = hyp_label # a string if 'label_color' in kwds: label_color = kwds.pop('label_color') else: label_color = 'black' if 'label_fontsize' in kwds: label_fontsize = kwds.pop('label_fontsize') else: label_fontsize = 14 if 'label_offset' in kwds: has_offset = True label_offset = kwds.pop('label_offset') else: has_offset = False # give default values below if 'point_size' in kwds: pt_size = kwds.pop('point_size') else: pt_size = 50 if 'ranges' in kwds: ranges_set = True ranges = kwds.pop('ranges') else: ranges_set = False # give default values below # the extra keywords have now been handled # now create the plot if hyperplane.dimension() == 0: # a point on a line x, = hyperplane.A() d = hyperplane.b() p = point((d/x,0), size = pt_size, **kwds) if has_hyp_label: if not has_offset: label_offset = 0.1 p += text(label, (d/x,label_offset), color=label_color,fontsize=label_fontsize) p += text('',(d/x,label_offset+0.4)) # add space at top if 'ymax' not in kwds: kwds['ymax'] = 0.5 elif hyperplane.dimension() == 1: # a line in the plane pnt = hyperplane.point() w = hyperplane.linear_part().matrix() x, y = hyperplane.A() d = hyperplane.b() t = SR.var('t') if ranges_set: if type(ranges) in [list,tuple]: t0, t1 = ranges else: # ranges should be a single positive number t0, t1 = -ranges, ranges else: # default t0, t1 = -3, 3 p = parametric_plot(pnt+t*w[0], (t,t0,t1), **kwds) if has_hyp_label: if has_offset: b0, b1 = label_offset else: b0, b1 = 0, 0.2 label = text(label,(pnt[0]+b0,pnt[1]+b1), color=label_color,fontsize=label_fontsize) p += label elif hyperplane.dimension() == 2: # a plane in 3-space pnt = hyperplane.point() w = hyperplane.linear_part().matrix() a, b, c = hyperplane.A() d = hyperplane.b() s,t = SR.var('s t') if ranges_set: if type(ranges) in [list,tuple]: s0, s1 = ranges[0] t0, t1 = ranges[1] else: # ranges should be a single positive integers s0, s1 = -ranges, ranges t0, t1 = -ranges, ranges else: # default s0, s1 = -3, 3 t0, t1 = -3, 3 p = parametric_plot3d(pnt+s*w[0]+t*w[1],(s,s0,s1),(t,t0,t1),**kwds) if has_hyp_label: if has_offset: b0, b1, b2 = label_offset else: b0, b1, b2 = 0, 0, 0 label = text3d(label,(pnt[0]+b0,pnt[1]+b1,pnt[2]+b2), color=label_color,fontsize=label_fontsize) p += label return p
def plot(self, chart=None, ambient_coords=None, mapping=None, color='blue', print_label=True, label=None, label_color=None, fontsize=10, label_offset=0.1, parameters=None, **extra_options): r""" Plot the vector in a Cartesian graph based on the coordinates of some ambient chart. The vector is drawn in terms of two (2D graphics) or three (3D graphics) coordinates of a given chart, called hereafter the *ambient chart*. The vector's base point `p` (or its image `\Phi(p)` by some differentiable mapping `\Phi`) must lie in the ambient chart's domain. If `\Phi` is different from the identity mapping, the vector actually depicted is `\mathrm{d}\Phi_p(v)`, where `v` is the current vector (``self``) (see the example of a vector tangent to the 2-sphere below, where `\Phi: S^2 \to \RR^3`). INPUT: - ``chart`` -- (default: ``None``) the ambient chart (see above); if ``None``, it is set to the default chart of the open set containing the point at which the vector (or the vector image via the differential `\mathrm{d}\Phi_p` of ``mapping``) is defined - ``ambient_coords`` -- (default: ``None``) tuple containing the 2 or 3 coordinates of the ambient chart in terms of which the plot is performed; if ``None``, all the coordinates of the ambient chart are considered - ``mapping`` -- (default: ``None``) :class:`~sage.manifolds.differentiable.diff_map.DiffMap`; differentiable mapping `\Phi` providing the link between the point `p` at which the vector is defined and the ambient chart ``chart``: the domain of ``chart`` must contain `\Phi(p)`; if ``None``, the identity mapping is assumed - ``scale`` -- (default: 1) value by which the length of the arrow representing the vector is multiplied - ``color`` -- (default: 'blue') color of the arrow representing the vector - ``print_label`` -- (boolean; default: ``True``) determines whether a label is printed next to the arrow representing the vector - ``label`` -- (string; default: ``None``) label printed next to the arrow representing the vector; if ``None``, the vector's symbol is used, if any - ``label_color`` -- (default: ``None``) color to print the label; if ``None``, the value of ``color`` is used - ``fontsize`` -- (default: 10) size of the font used to print the label - ``label_offset`` -- (default: 0.1) determines the separation between the vector arrow and the label - ``parameters`` -- (default: ``None``) dictionary giving the numerical values of the parameters that may appear in the coordinate expression of ``self`` (see example below) - ``**extra_options`` -- extra options for the arrow plot, like ``linestyle``, ``width`` or ``arrowsize`` (see :func:`~sage.plot.arrow.arrow2d` and :func:`~sage.plot.plot3d.shapes.arrow3d` for details) OUTPUT: - a graphic object, either an instance of :class:`~sage.plot.graphics.Graphics` for a 2D plot (i.e. based on 2 coordinates of ``chart``) or an instance of :class:`~sage.plot.plot3d.base.Graphics3d` for a 3D plot (i.e. based on 3 coordinates of ``chart``) EXAMPLES: Vector tangent to a 2-dimensional manifold:: sage: M = Manifold(2, 'M') sage: X.<x,y> = M.chart() sage: p = M((2,2), name='p') sage: Tp = M.tangent_space(p) sage: v = Tp((2, 1), name='v') ; v Tangent vector v at Point p on the 2-dimensional differentiable manifold M Plot of the vector alone (arrow + label):: sage: v.plot() Graphics object consisting of 2 graphics primitives Plot atop of the chart grid:: sage: X.plot() + v.plot() Graphics object consisting of 20 graphics primitives .. PLOT:: M = Manifold(2, 'M') X = M.chart('x y'); x, y = X[:] p = M((2,2), name='p'); Tp = M.tangent_space(p) v = Tp((2, 1), name='v') g = X.plot() + v.plot() sphinx_plot(g) Plots with various options:: sage: X.plot() + v.plot(color='green', scale=2, label='V') Graphics object consisting of 20 graphics primitives .. PLOT:: M = Manifold(2, 'M') X = M.chart('x y'); x, y = X[:] p = M((2,2), name='p'); Tp = M.tangent_space(p) v = Tp((2, 1), name='v') g = X.plot() + v.plot(color='green', scale=2, label='V') sphinx_plot(g) :: sage: X.plot() + v.plot(print_label=False) Graphics object consisting of 19 graphics primitives .. PLOT:: M = Manifold(2, 'M') X = M.chart('x y'); x, y = X[:] p = M((2,2), name='p'); Tp = M.tangent_space(p) v = Tp((2, 1), name='v') g = X.plot() + v.plot(print_label=False) sphinx_plot(g) :: sage: X.plot() + v.plot(color='green', label_color='black', ....: fontsize=20, label_offset=0.2) Graphics object consisting of 20 graphics primitives .. PLOT:: M = Manifold(2, 'M') X = M.chart('x y'); x, y = X[:] p = M((2,2), name='p'); Tp = M.tangent_space(p) v = Tp((2, 1), name='v') g = X.plot() + v.plot(color='green', label_color='black', fontsize=20, label_offset=0.2) sphinx_plot(g) :: sage: X.plot() + v.plot(linestyle=':', width=4, arrowsize=8, ....: fontsize=20) Graphics object consisting of 20 graphics primitives .. PLOT:: M = Manifold(2, 'M') X = M.chart('x y'); x, y = X[:] p = M((2,2), name='p'); Tp = M.tangent_space(p) v = Tp((2, 1), name='v') g = X.plot() + v.plot(linestyle=':', width=4, arrowsize=8, fontsize=20) sphinx_plot(g) Plot with specific values of some free parameters:: sage: var('a b') (a, b) sage: v = Tp((1+a, -b^2), name='v') ; v.display() v = (a + 1) d/dx - b^2 d/dy sage: X.plot() + v.plot(parameters={a: -2, b: 3}) Graphics object consisting of 20 graphics primitives Special case of the zero vector:: sage: v = Tp.zero() ; v Tangent vector zero at Point p on the 2-dimensional differentiable manifold M sage: X.plot() + v.plot() Graphics object consisting of 19 graphics primitives Vector tangent to a 4-dimensional manifold:: sage: M = Manifold(4, 'M') sage: X.<t,x,y,z> = M.chart() sage: p = M((0,1,2,3), name='p') sage: Tp = M.tangent_space(p) sage: v = Tp((5,4,3,2), name='v') ; v Tangent vector v at Point p on the 4-dimensional differentiable manifold M We cannot make a 4D plot directly:: sage: v.plot() Traceback (most recent call last): ... ValueError: the number of coordinates involved in the plot must be either 2 or 3, not 4 Rather, we have to select some chart coordinates for the plot, via the argument ``ambient_coords``. For instance, for a 2-dimensional plot in terms of the coordinates `(x, y)`:: sage: v.plot(ambient_coords=(x,y)) Graphics object consisting of 2 graphics primitives .. PLOT:: M = Manifold(4, 'M') X = M.chart('t x y z'); t,x,y,z = X[:] p = M((0,1,2,3), name='p'); Tp = M.tangent_space(p) v = Tp((5,4,3,2), name='v') g = X.plot(ambient_coords=(x,y)) + v.plot(ambient_coords=(x,y)) sphinx_plot(g) This plot involves only the components `v^x` and `v^y` of `v`. Similarly, for a 3-dimensional plot in terms of the coordinates `(t, x, y)`:: sage: g = v.plot(ambient_coords=(t,x,z)) sage: print(g) Graphics3d Object This plot involves only the components `v^t`, `v^x` and `v^z` of `v`. A nice 3D view atop the coordinate grid is obtained via:: sage: (X.plot(ambient_coords=(t,x,z)) # long time ....: + v.plot(ambient_coords=(t,x,z), ....: label_offset=0.5, width=6)) Graphics3d Object .. PLOT:: M = Manifold(4, 'M') X = M.chart('t x y z'); t,x,y,z = X[:] p = M((0,1,2,3), name='p'); Tp = M.tangent_space(p) v = Tp((5,4,3,2), name='v') g = X.plot(ambient_coords=(t,x,z)) + v.plot(ambient_coords=(t,x,z), label_offset=0.5, width=6) sphinx_plot(g) An example of plot via a differential mapping: plot of a vector tangent to a 2-sphere viewed in `\RR^3`:: sage: S2 = Manifold(2, 'S^2') sage: U = S2.open_subset('U') # the open set covered by spherical coord. sage: XS.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi') sage: R3 = Manifold(3, 'R^3') sage: X3.<x,y,z> = R3.chart() sage: F = S2.diff_map(R3, {(XS, X3): [sin(th)*cos(ph), ....: sin(th)*sin(ph), ....: cos(th)]}, name='F') sage: F.display() # the standard embedding of S^2 into R^3 F: S^2 --> R^3 on U: (th, ph) |--> (x, y, z) = (cos(ph)*sin(th), sin(ph)*sin(th), cos(th)) sage: p = U.point((pi/4, 7*pi/4), name='p') sage: v = XS.frame()[1].at(p) ; v # the coordinate vector d/dphi at p Tangent vector d/dph at Point p on the 2-dimensional differentiable manifold S^2 sage: graph_v = v.plot(mapping=F) sage: graph_S2 = XS.plot(chart=X3, mapping=F, number_values=9) # long time sage: graph_v + graph_S2 # long time Graphics3d Object .. PLOT:: S2 = Manifold(2, 'S^2') U = S2.open_subset('U') XS = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi') th, ph = XS[:] R3 = Manifold(3, 'R^3') X3 = R3.chart('x y z') F = S2.diff_map(R3, {(XS, X3): [sin(th)*cos(ph), sin(th)*sin(ph), cos(th)]}, name='F') p = U.point((pi/4, 7*pi/4), name='p') v = XS.frame()[1].at(p) graph_v = v.plot(mapping=F) graph_S2 = XS.plot(chart=X3, mapping=F, number_values=9) sphinx_plot(graph_v + graph_S2) """ from sage.plot.arrow import arrow2d from sage.plot.text import text from sage.plot.graphics import Graphics from sage.plot.plot3d.shapes import arrow3d from sage.plot.plot3d.shapes2 import text3d from sage.misc.functional import numerical_approx from sage.manifolds.differentiable.chart import DiffChart scale = extra_options.pop("scale") # # The "effective" vector to be plotted # if mapping is None: eff_vector = self base_point = self._point else: #!# check # For efficiency, the method FiniteRankFreeModuleMorphism._call_() # is called instead of FiniteRankFreeModuleMorphism.__call__() eff_vector = mapping.differential(self._point)._call_(self) base_point = mapping(self._point) # # The chart w.r.t. which the vector is plotted # if chart is None: chart = base_point.parent().default_chart() elif not isinstance(chart, DiffChart): raise TypeError("{} is not a chart".format(chart)) # # Coordinates of the above chart w.r.t. which the vector is plotted # if ambient_coords is None: ambient_coords = chart[:] # all chart coordinates are used n_pc = len(ambient_coords) if n_pc != 2 and n_pc !=3: raise ValueError("the number of coordinates involved in the " + "plot must be either 2 or 3, not {}".format(n_pc)) # indices coordinates involved in the plot: ind_pc = [chart[:].index(pc) for pc in ambient_coords] # # Components of the vector w.r.t. the chart frame # basis = chart.frame().at(base_point) vcomp = eff_vector.comp(basis=basis)[:] xp = base_point.coord(chart=chart) # # The arrow # resu = Graphics() if parameters is None: coord_tail = [numerical_approx(xp[i]) for i in ind_pc] coord_head = [numerical_approx(xp[i] + scale*vcomp[i]) for i in ind_pc] else: coord_tail = [numerical_approx(xp[i].substitute(parameters)) for i in ind_pc] coord_head = [numerical_approx( (xp[i] + scale*vcomp[i]).substitute(parameters)) for i in ind_pc] if coord_head != coord_tail: if n_pc == 2: resu += arrow2d(tailpoint=coord_tail, headpoint=coord_head, color=color, **extra_options) else: resu += arrow3d(coord_tail, coord_head, color=color, **extra_options) # # The label # if print_label: if label is None: if n_pc == 2 and self._latex_name is not None: label = r'$' + self._latex_name + r'$' if n_pc == 3 and self._name is not None: label = self._name if label is not None: xlab = [xh + label_offset for xh in coord_head] if label_color is None: label_color = color if n_pc == 2: resu += text(label, xlab, fontsize=fontsize, color=label_color) else: resu += text3d(label, xlab, fontsize=fontsize, color=label_color) return resu
def plot(self, chart=None, ambient_coords=None, mapping=None, size=10, color='black', label=None, label_color=None, fontsize=10, label_offset=0.1, parameters=None): r""" Plot the current point (``self``) in a Cartesian graph based on the coordinates of some ambient chart. The point is drawn in terms of two (2D graphics) or three (3D graphics) coordinates of a given chart, called hereafter the *ambient chart*. The domain of the ambient chart must contain the point, or its image by a differentiable mapping `\Phi`. INPUT: - ``chart`` -- (default: ``None``) the ambient chart (see above); if ``None``, the ambient chart is set the default chart of ``self.containing_set()`` - ``ambient_coords`` -- (default: ``None``) tuple containing the 2 or 3 coordinates of the ambient chart in terms of which the plot is performed; if ``None``, all the coordinates of the ambient chart are considered - ``mapping`` -- (default: ``None``) differentiable mapping `\Phi` (instance of :class:`~sage.geometry.manifolds.diffmapping.DiffMapping`) providing the link between the point `p` represented by ``self`` and the ambient chart ``chart``: the domain of ``chart`` must contain `\Phi(p)`; if ``None``, the identity mapping is assumed - ``size`` -- (default: 10) size of the point once drawn as a small disk or sphere - ``color`` -- (default: 'black') color of the point - ``label`` -- (default: ``None``) label printed next to the point; if ``None``, the point's name is used. - ``label_color`` -- (default: ``None``) color to print the label; if ``None``, the value of ``color`` is used - ``fontsize`` -- (default: 10) size of the font used to print the label - ``label_offset`` -- (default: 0.1) determines the separation between the point and its label - ``parameters`` -- (default: ``None``) dictionary giving the numerical values of the parameters that may appear in the point coordinates OUTPUT: - a graphic object, either an instance of :class:`~sage.plot.graphics.Graphics` for a 2D plot (i.e. based on 2 coordinates of the ambient chart) or an instance of :class:`~sage.plot.plot3d.base.Graphics3d` for a 3D plot (i.e. based on 3 coordinates of the ambient chart) EXAMPLES: Drawing a point on a 2-dimensional manifold:: sage: M = Manifold(2, 'M') sage: X.<x,y> = M.chart() sage: p = M.point((1,3), name='p') sage: g = p.plot(X) sage: print g Graphics object consisting of 2 graphics primitives sage: gX = X.plot() # plot of the coordinate grid sage: show(g+gX) # display of the point atop the coordinate grid Actually, since ``X`` is the default chart of the open set in which ``p`` has been defined, it can be skipped in the arguments of ``plot``:: sage: g = p.plot() sage: show(g+gX) Call with some options:: sage: g = p.plot(chart=X, size=40, color='green', label='$P$', ....: label_color='blue', fontsize=20, label_offset=0.3) sage: show(g+gX) Use of the ``parameters`` option to set a numerical value of some symbolic variable:: sage: a = var('a') sage: q = M.point((a,2*a), name='q') sage: gq = q.plot(parameters={a:-2}) sage: show(g+gX+gq) The numerical value is used only for the plot:: sage: q.coord() (a, 2*a) Drawing a point on a 3-dimensional manifold:: sage: M = Manifold(3, 'M') sage: X.<x,y,z> = M.chart() sage: p = M.point((2,1,3), name='p') sage: g = p.plot() sage: print g Graphics3d Object sage: gX = X.plot(nb_values=5) # coordinate mesh cube sage: show(g+gX) # display of the point atop the coordinate mesh Call with some options:: sage: g = p.plot(chart=X, size=40, color='green', label='P_1', ....: label_color='blue', fontsize=20, label_offset=0.3) sage: show(g+gX) An example of plot via a differential mapping: plot of a point on a 2-sphere viewed in the 3-dimensional space ``M``:: sage: S2 = Manifold(2, 'S^2') sage: U = S2.open_subset('U') # the open set covered by spherical coord. sage: XS.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi') sage: p = U.point((pi/4, pi/8), name='p') sage: F = S2.diff_mapping(M, {(XS, X): [sin(th)*cos(ph), ....: sin(th)*sin(ph), cos(th)]}, name='F') sage: F.display() F: S^2 --> M on U: (th, ph) |--> (x, y, z) = (cos(ph)*sin(th), sin(ph)*sin(th), cos(th)) sage: g = p.plot(chart=X, mapping=F) sage: gS2 = XS.plot(chart=X, mapping=F, nb_values=9) sage: show(g+gS2) Use of the option ``ambient_coords`` for plots on a 4-dimensional manifold:: sage: M = Manifold(4, 'M') sage: X.<t,x,y,z> = M.chart() sage: p = M.point((1,2,3,4), name='p') sage: g = p.plot(X, ambient_coords=(t,x,y)) # the coordinate z is skipped sage: gX = X.plot(X, ambient_coords=(t,x,y), nb_values=5) sage: show(g+gX) # 3D plot sage: g = p.plot(X, ambient_coords=(t,y,z)) # the coordinate x is skipped sage: gX = X.plot(X, ambient_coords=(t,y,z), nb_values=5) sage: show(g+gX) # 3D plot sage: g = p.plot(X, ambient_coords=(y,z)) # the coordinates t and x are skipped sage: gX = X.plot(X, ambient_coords=(y,z)) sage: show(g+gX) # 2D plot """ from sage.plot.point import point2d from sage.plot.text import text from sage.plot.graphics import Graphics from sage.plot.plot3d.shapes2 import point3d, text3d from sage.geometry.manifolds.chart import Chart # The ambient chart: if chart is None: chart = self.containing_set().default_chart() elif not isinstance(chart, Chart): raise TypeError("the argument 'chart' must be a coordinate chart") # The effective point to be plotted: if mapping is None: eff_point = self else: eff_point = mapping(self) # The coordinates of the ambient chart used for the plot: if ambient_coords is None: ambient_coords = chart._xx elif not isinstance(ambient_coords, tuple): ambient_coords = tuple(ambient_coords) nca = len(ambient_coords) if nca != 2 and nca != 3: raise TypeError("Bad number of ambient coordinates: " + str(nca)) # The point coordinates: coords = eff_point.coord(chart) xx = chart[:] xp = [coords[xx.index(c)] for c in ambient_coords] if parameters is not None: xps = [coord.substitute(parameters) for coord in xp] xp = xps xlab = [coord + label_offset for coord in xp] if label_color is None: label_color = color resu = Graphics() if nca == 2: if label is None: label = r'$' + self._latex_name + r'$' resu += point2d(xp, color=color, size=size) + \ text(label, xlab, fontsize=fontsize, color=label_color) else: if label is None: label = self._name resu += point3d(xp, color=color, size=size) + \ text3d(label, xlab, fontsize=fontsize, color=label_color) return resu
def plot(self, chart=None, ambient_coords=None, mapping=None, label=None, parameters=None, **kwds): r""" For real manifolds, plot ``self`` in a Cartesian graph based on the coordinates of some ambient chart. The point is drawn in terms of two (2D graphics) or three (3D graphics) coordinates of a given chart, called hereafter the *ambient chart*. The domain of the ambient chart must contain the point, or its image by a continuous manifold map `\Phi`. INPUT: - ``chart`` -- (default: ``None``) the ambient chart (see above); if ``None``, the ambient chart is set the default chart of ``self.parent()`` - ``ambient_coords`` -- (default: ``None``) tuple containing the 2 or 3 coordinates of the ambient chart in terms of which the plot is performed; if ``None``, all the coordinates of the ambient chart are considered - ``mapping`` -- (default: ``None``) :class:`~sage.manifolds.continuous_map.ContinuousMap`; continuous manifold map `\Phi` providing the link between the current point `p` and the ambient chart ``chart``: the domain of ``chart`` must contain `\Phi(p)`; if ``None``, the identity map is assumed - ``label`` -- (default: ``None``) label printed next to the point; if ``None``, the point's name is used - ``parameters`` -- (default: ``None``) dictionary giving the numerical values of the parameters that may appear in the point coordinates - ``size`` -- (default: 10) size of the point once drawn as a small disk or sphere - ``color`` -- (default: ``'black'``) color of the point - ``label_color`` -- (default: ``None``) color to print the label; if ``None``, the value of ``color`` is used - ``fontsize`` -- (default: 10) size of the font used to print the label - ``label_offset`` -- (default: 0.1) determines the separation between the point and its label OUTPUT: - a graphic object, either an instance of :class:`~sage.plot.graphics.Graphics` for a 2D plot (i.e. based on 2 coordinates of the ambient chart) or an instance of :class:`~sage.plot.plot3d.base.Graphics3d` for a 3D plot (i.e. based on 3 coordinates of the ambient chart) EXAMPLES: Drawing a point on a 2-dimensional manifold:: sage: M = Manifold(2, 'M', structure='topological') sage: X.<x,y> = M.chart() sage: p = M.point((1,3), name='p') sage: g = p.plot(X) sage: print(g) Graphics object consisting of 2 graphics primitives sage: gX = X.plot(max_range=4) # plot of the coordinate grid sage: g + gX # display of the point atop the coordinate grid Graphics object consisting of 20 graphics primitives .. PLOT:: M = Manifold(2, 'M', structure='topological') X = M.chart('x y'); x,y = X[:] p = M.point((1,3), name='p') g = p.plot(X) gX = X.plot(max_range=4) sphinx_plot(g+gX) Actually, since ``X`` is the default chart of the open set in which ``p`` has been defined, it can be skipped in the arguments of ``plot``:: sage: g = p.plot() sage: g + gX Graphics object consisting of 20 graphics primitives Call with some options:: sage: g = p.plot(chart=X, size=40, color='green', label='$P$', ....: label_color='blue', fontsize=20, label_offset=0.3) sage: g + gX Graphics object consisting of 20 graphics primitives .. PLOT:: M = Manifold(2, 'M', structure='topological') X = M.chart('x y'); x,y = X[:] p = M.point((1,3), name='p') g = p.plot(chart=X, size=40, color='green', label='$P$', \ label_color='blue', fontsize=20, label_offset=0.3) gX = X.plot(max_range=4) sphinx_plot(g+gX) Use of the ``parameters`` option to set a numerical value of some symbolic variable:: sage: a = var('a') sage: q = M.point((a,2*a), name='q') sage: gq = q.plot(parameters={a:-2}, label_offset=0.2) sage: g + gX + gq Graphics object consisting of 22 graphics primitives .. PLOT:: M = Manifold(2, 'M', structure='topological') X = M.chart('x y'); x,y = X[:] p = M.point((1,3), name='p') g = p.plot(chart=X, size=40, color='green', label='$P$', \ label_color='blue', fontsize=20, label_offset=0.3) var('a') q = M.point((a,2*a), name='q') gq = q.plot(parameters={a:-2}, label_offset=0.2) gX = X.plot(max_range=4) sphinx_plot(g+gX+gq) The numerical value is used only for the plot:: sage: q.coord() (a, 2*a) Drawing a point on a 3-dimensional manifold:: sage: M = Manifold(3, 'M', structure='topological') sage: X.<x,y,z> = M.chart() sage: p = M.point((2,1,3), name='p') sage: g = p.plot() sage: print(g) Graphics3d Object sage: gX = X.plot(number_values=5) # coordinate mesh cube sage: g + gX # display of the point atop the coordinate mesh Graphics3d Object Call with some options:: sage: g = p.plot(chart=X, size=40, color='green', label='P_1', ....: label_color='blue', fontsize=20, label_offset=0.3) sage: g + gX Graphics3d Object An example of plot via a mapping: plot of a point on a 2-sphere viewed in the 3-dimensional space ``M``:: sage: S2 = Manifold(2, 'S^2', structure='topological') sage: U = S2.open_subset('U') # the open set covered by spherical coord. sage: XS.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi') sage: p = U.point((pi/4, pi/8), name='p') sage: F = S2.continuous_map(M, {(XS, X): [sin(th)*cos(ph), ....: sin(th)*sin(ph), cos(th)]}, name='F') sage: F.display() F: S^2 --> M on U: (th, ph) |--> (x, y, z) = (cos(ph)*sin(th), sin(ph)*sin(th), cos(th)) sage: g = p.plot(chart=X, mapping=F) sage: gS2 = XS.plot(chart=X, mapping=F, number_values=9) sage: g + gS2 Graphics3d Object Use of the option ``ambient_coords`` for plots on a 4-dimensional manifold:: sage: M = Manifold(4, 'M', structure='topological') sage: X.<t,x,y,z> = M.chart() sage: p = M.point((1,2,3,4), name='p') sage: g = p.plot(X, ambient_coords=(t,x,y), label_offset=0.4) # the coordinate z is skipped sage: gX = X.plot(X, ambient_coords=(t,x,y), number_values=5) # long time sage: g + gX # 3D plot # long time Graphics3d Object sage: g = p.plot(X, ambient_coords=(t,y,z), label_offset=0.4) # the coordinate x is skipped sage: gX = X.plot(X, ambient_coords=(t,y,z), number_values=5) # long time sage: g + gX # 3D plot # long time Graphics3d Object sage: g = p.plot(X, ambient_coords=(y,z), label_offset=0.4) # the coordinates t and x are skipped sage: gX = X.plot(X, ambient_coords=(y,z)) sage: g + gX # 2D plot Graphics object consisting of 20 graphics primitives .. PLOT:: M = Manifold(4, 'M', structure='topological') X = M.chart('t x y z'); t,x,y,z = X[:] p = M.point((1,2,3,4), name='p') g = p.plot(X, ambient_coords=(y,z), label_offset=0.4) gX = X.plot(X, ambient_coords=(y,z)) sphinx_plot(g+gX) """ from sage.plot.point import point2d from sage.plot.text import text from sage.plot.graphics import Graphics from sage.plot.plot3d.shapes2 import point3d, text3d from sage.manifolds.chart import Chart if self._manifold.base_field_type() != 'real': raise NotImplementedError( 'plot of points on manifolds over fields different' ' from the real field is not implemented') # The ambient chart: if chart is None: chart = self.parent().default_chart() elif not isinstance(chart, Chart): raise TypeError("the argument 'chart' must be a coordinate chart") # The effective point to be plotted: if mapping is None: eff_point = self else: eff_point = mapping(self) # The coordinates of the ambient chart used for the plot: if ambient_coords is None: ambient_coords = chart[:] elif not isinstance(ambient_coords, tuple): ambient_coords = tuple(ambient_coords) nca = len(ambient_coords) if nca != 2 and nca != 3: raise TypeError( "invalid number of ambient coordinates: {}".format(nca)) # Extract the kwds options size = kwds['size'] color = kwds['color'] label_color = kwds['label_color'] fontsize = kwds['fontsize'] label_offset = kwds['label_offset'] # The point coordinates: coords = eff_point.coord(chart) xx = chart[:] xp = [coords[xx.index(c)] for c in ambient_coords] if parameters is not None: xps = [coord.substitute(parameters) for coord in xp] xp = xps xlab = [coord + label_offset for coord in xp] if label_color is None: label_color = color resu = Graphics() if nca == 2: if label is None: label = r'$' + self._latex_name + r'$' resu += (point2d(xp, color=color, size=size) + text(label, xlab, fontsize=fontsize, color=label_color)) else: if label is None: label = self._name resu += (point3d(xp, color=color, size=size) + text3d(label, xlab, fontsize=fontsize, color=label_color)) return resu