passagemath-symbolics 10.6.40__cp314-cp314t-macosx_13_0_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-symbolics might be problematic. Click here for more details.
- passagemath_symbolics/.dylibs/libgmp.10.dylib +0 -0
- passagemath_symbolics/__init__.py +3 -0
- passagemath_symbolics-10.6.40.dist-info/METADATA +187 -0
- passagemath_symbolics-10.6.40.dist-info/RECORD +172 -0
- passagemath_symbolics-10.6.40.dist-info/WHEEL +6 -0
- passagemath_symbolics-10.6.40.dist-info/top_level.txt +3 -0
- sage/all__sagemath_symbolics.py +17 -0
- sage/calculus/all.py +14 -0
- sage/calculus/calculus.py +2826 -0
- sage/calculus/desolvers.py +1866 -0
- sage/calculus/predefined.py +51 -0
- sage/calculus/tests.py +225 -0
- sage/calculus/var.cpython-314t-darwin.so +0 -0
- sage/calculus/var.pyx +401 -0
- sage/dynamics/all__sagemath_symbolics.py +6 -0
- sage/dynamics/complex_dynamics/all.py +5 -0
- sage/dynamics/complex_dynamics/mandel_julia.py +765 -0
- sage/dynamics/complex_dynamics/mandel_julia_helper.cpython-314t-darwin.so +0 -0
- sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +1035 -0
- sage/ext/all__sagemath_symbolics.py +1 -0
- sage/ext_data/kenzo/CP2.txt +45 -0
- sage/ext_data/kenzo/CP3.txt +349 -0
- sage/ext_data/kenzo/CP4.txt +4774 -0
- sage/ext_data/kenzo/README.txt +49 -0
- sage/ext_data/kenzo/S4.txt +20 -0
- sage/ext_data/magma/latex/latex.m +1021 -0
- sage/ext_data/magma/latex/latex.spec +1 -0
- sage/ext_data/magma/sage/basic.m +356 -0
- sage/ext_data/magma/sage/sage.spec +1 -0
- sage/ext_data/magma/spec +9 -0
- sage/geometry/all__sagemath_symbolics.py +8 -0
- sage/geometry/hyperbolic_space/all.py +5 -0
- sage/geometry/hyperbolic_space/hyperbolic_coercion.py +743 -0
- sage/geometry/hyperbolic_space/hyperbolic_constants.py +5 -0
- sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +2409 -0
- sage/geometry/hyperbolic_space/hyperbolic_interface.py +206 -0
- sage/geometry/hyperbolic_space/hyperbolic_isometry.py +1082 -0
- sage/geometry/hyperbolic_space/hyperbolic_model.py +1502 -0
- sage/geometry/hyperbolic_space/hyperbolic_point.py +621 -0
- sage/geometry/riemannian_manifolds/all.py +7 -0
- sage/geometry/riemannian_manifolds/parametrized_surface3d.py +1632 -0
- sage/geometry/riemannian_manifolds/surface3d_generators.py +461 -0
- sage/interfaces/all__sagemath_symbolics.py +1 -0
- sage/interfaces/magma.py +3017 -0
- sage/interfaces/magma_free.py +92 -0
- sage/interfaces/maple.py +1397 -0
- sage/interfaces/mathematica.py +1345 -0
- sage/interfaces/mathics.py +1312 -0
- sage/interfaces/sympy.py +1398 -0
- sage/interfaces/sympy_wrapper.py +197 -0
- sage/interfaces/tides.py +938 -0
- sage/libs/all__sagemath_symbolics.py +6 -0
- sage/manifolds/all.py +7 -0
- sage/manifolds/calculus_method.py +555 -0
- sage/manifolds/catalog.py +437 -0
- sage/manifolds/chart.py +4019 -0
- sage/manifolds/chart_func.py +3419 -0
- sage/manifolds/continuous_map.py +2183 -0
- sage/manifolds/continuous_map_image.py +155 -0
- sage/manifolds/differentiable/affine_connection.py +2475 -0
- sage/manifolds/differentiable/all.py +1 -0
- sage/manifolds/differentiable/automorphismfield.py +1383 -0
- sage/manifolds/differentiable/automorphismfield_group.py +604 -0
- sage/manifolds/differentiable/bundle_connection.py +1445 -0
- sage/manifolds/differentiable/characteristic_cohomology_class.py +1840 -0
- sage/manifolds/differentiable/chart.py +1241 -0
- sage/manifolds/differentiable/curve.py +1028 -0
- sage/manifolds/differentiable/de_rham_cohomology.py +541 -0
- sage/manifolds/differentiable/degenerate.py +559 -0
- sage/manifolds/differentiable/degenerate_submanifold.py +1671 -0
- sage/manifolds/differentiable/diff_form.py +1658 -0
- sage/manifolds/differentiable/diff_form_module.py +1062 -0
- sage/manifolds/differentiable/diff_map.py +1315 -0
- sage/manifolds/differentiable/differentiable_submanifold.py +291 -0
- sage/manifolds/differentiable/examples/all.py +1 -0
- sage/manifolds/differentiable/examples/euclidean.py +2517 -0
- sage/manifolds/differentiable/examples/real_line.py +897 -0
- sage/manifolds/differentiable/examples/sphere.py +1186 -0
- sage/manifolds/differentiable/examples/symplectic_space.py +187 -0
- sage/manifolds/differentiable/examples/symplectic_space_test.py +40 -0
- sage/manifolds/differentiable/integrated_curve.py +4035 -0
- sage/manifolds/differentiable/levi_civita_connection.py +841 -0
- sage/manifolds/differentiable/manifold.py +4254 -0
- sage/manifolds/differentiable/manifold_homset.py +1826 -0
- sage/manifolds/differentiable/metric.py +3032 -0
- sage/manifolds/differentiable/mixed_form.py +1507 -0
- sage/manifolds/differentiable/mixed_form_algebra.py +559 -0
- sage/manifolds/differentiable/multivector_module.py +800 -0
- sage/manifolds/differentiable/multivectorfield.py +1520 -0
- sage/manifolds/differentiable/poisson_tensor.py +268 -0
- sage/manifolds/differentiable/pseudo_riemannian.py +755 -0
- sage/manifolds/differentiable/pseudo_riemannian_submanifold.py +1839 -0
- sage/manifolds/differentiable/scalarfield.py +1343 -0
- sage/manifolds/differentiable/scalarfield_algebra.py +472 -0
- sage/manifolds/differentiable/symplectic_form.py +910 -0
- sage/manifolds/differentiable/symplectic_form_test.py +220 -0
- sage/manifolds/differentiable/tangent_space.py +412 -0
- sage/manifolds/differentiable/tangent_vector.py +616 -0
- sage/manifolds/differentiable/tensorfield.py +4665 -0
- sage/manifolds/differentiable/tensorfield_module.py +963 -0
- sage/manifolds/differentiable/tensorfield_paral.py +2450 -0
- sage/manifolds/differentiable/tensorfield_paral_test.py +16 -0
- sage/manifolds/differentiable/vector_bundle.py +1728 -0
- sage/manifolds/differentiable/vectorfield.py +1717 -0
- sage/manifolds/differentiable/vectorfield_module.py +2445 -0
- sage/manifolds/differentiable/vectorframe.py +1832 -0
- sage/manifolds/family.py +270 -0
- sage/manifolds/local_frame.py +1490 -0
- sage/manifolds/manifold.py +3090 -0
- sage/manifolds/manifold_homset.py +452 -0
- sage/manifolds/operators.py +359 -0
- sage/manifolds/point.py +994 -0
- sage/manifolds/scalarfield.py +3718 -0
- sage/manifolds/scalarfield_algebra.py +629 -0
- sage/manifolds/section.py +3111 -0
- sage/manifolds/section_module.py +831 -0
- sage/manifolds/structure.py +229 -0
- sage/manifolds/subset.py +2764 -0
- sage/manifolds/subsets/all.py +1 -0
- sage/manifolds/subsets/closure.py +131 -0
- sage/manifolds/subsets/pullback.py +885 -0
- sage/manifolds/topological_submanifold.py +891 -0
- sage/manifolds/trivialization.py +733 -0
- sage/manifolds/utilities.py +1348 -0
- sage/manifolds/vector_bundle.py +1342 -0
- sage/manifolds/vector_bundle_fiber.py +332 -0
- sage/manifolds/vector_bundle_fiber_element.py +111 -0
- sage/matrix/all__sagemath_symbolics.py +1 -0
- sage/matrix/matrix_symbolic_dense.cpython-314t-darwin.so +0 -0
- sage/matrix/matrix_symbolic_dense.pxd +6 -0
- sage/matrix/matrix_symbolic_dense.pyx +1022 -0
- sage/matrix/matrix_symbolic_sparse.cpython-314t-darwin.so +0 -0
- sage/matrix/matrix_symbolic_sparse.pxd +6 -0
- sage/matrix/matrix_symbolic_sparse.pyx +1029 -0
- sage/modules/all__sagemath_symbolics.py +1 -0
- sage/modules/vector_callable_symbolic_dense.py +105 -0
- sage/modules/vector_symbolic_dense.py +116 -0
- sage/modules/vector_symbolic_sparse.py +118 -0
- sage/rings/all__sagemath_symbolics.py +4 -0
- sage/rings/asymptotic/all.py +6 -0
- sage/rings/asymptotic/asymptotic_expansion_generators.py +1485 -0
- sage/rings/asymptotic/asymptotic_ring.py +4858 -0
- sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py +4153 -0
- sage/rings/asymptotic/growth_group.py +5373 -0
- sage/rings/asymptotic/growth_group_cartesian.py +1400 -0
- sage/rings/asymptotic/term_monoid.py +5237 -0
- sage/rings/function_field/all__sagemath_symbolics.py +2 -0
- sage/rings/polynomial/all__sagemath_symbolics.py +1 -0
- sage/symbolic/all.py +15 -0
- sage/symbolic/assumptions.py +985 -0
- sage/symbolic/benchmark.py +93 -0
- sage/symbolic/callable.py +459 -0
- sage/symbolic/complexity_measures.py +35 -0
- sage/symbolic/constants.py +1287 -0
- sage/symbolic/expression_conversion_algebraic.py +310 -0
- sage/symbolic/expression_conversion_sympy.py +317 -0
- sage/symbolic/expression_conversions.py +1713 -0
- sage/symbolic/function_factory.py +355 -0
- sage/symbolic/integration/all.py +1 -0
- sage/symbolic/integration/external.py +270 -0
- sage/symbolic/integration/integral.py +1115 -0
- sage/symbolic/maxima_wrapper.py +162 -0
- sage/symbolic/operators.py +267 -0
- sage/symbolic/random_tests.py +462 -0
- sage/symbolic/relation.py +1907 -0
- sage/symbolic/ring.cpython-314t-darwin.so +0 -0
- sage/symbolic/ring.pxd +5 -0
- sage/symbolic/ring.pyx +1396 -0
- sage/symbolic/subring.py +1025 -0
- sage/symbolic/symengine.py +19 -0
- sage/symbolic/tests.py +40 -0
- sage/symbolic/units.py +1470 -0
|
@@ -0,0 +1,1028 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-symbolics
|
|
2
|
+
r"""
|
|
3
|
+
Curves in Manifolds
|
|
4
|
+
|
|
5
|
+
Given a differentiable manifold `M`, a *differentiable curve* in
|
|
6
|
+
`M` is a differentiable mapping
|
|
7
|
+
|
|
8
|
+
.. MATH::
|
|
9
|
+
|
|
10
|
+
\gamma: I \longrightarrow M,
|
|
11
|
+
|
|
12
|
+
where `I` is an interval of `\RR`.
|
|
13
|
+
|
|
14
|
+
Differentiable curves are implemented by :class:`DifferentiableCurve`.
|
|
15
|
+
|
|
16
|
+
AUTHORS:
|
|
17
|
+
|
|
18
|
+
- Eric Gourgoulhon (2015): initial version
|
|
19
|
+
- Travis Scrimshaw (2016): review tweaks
|
|
20
|
+
|
|
21
|
+
REFERENCES:
|
|
22
|
+
|
|
23
|
+
- Chap. 1 of [KN1963]_
|
|
24
|
+
- Chap. 3 of [Lee2013]_
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
#*****************************************************************************
|
|
28
|
+
# Copyright (C) 2015 Eric Gourgoulhon <eric.gourgoulhon@obspm.fr>
|
|
29
|
+
#
|
|
30
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
31
|
+
# as published by the Free Software Foundation; either version 2 of
|
|
32
|
+
# the License, or (at your option) any later version.
|
|
33
|
+
# http://www.gnu.org/licenses/
|
|
34
|
+
#*****************************************************************************
|
|
35
|
+
|
|
36
|
+
from sage.manifolds.differentiable.diff_map import DiffMap
|
|
37
|
+
from sage.manifolds.point import ManifoldPoint
|
|
38
|
+
from sage.misc.decorators import options
|
|
39
|
+
from sage.misc.latex import latex
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class DifferentiableCurve(DiffMap):
|
|
43
|
+
r"""
|
|
44
|
+
Curve in a differentiable manifold.
|
|
45
|
+
|
|
46
|
+
Given a differentiable manifold `M`, a *differentiable curve* in
|
|
47
|
+
`M` is a differentiable map
|
|
48
|
+
|
|
49
|
+
.. MATH::
|
|
50
|
+
|
|
51
|
+
\gamma: I \longrightarrow M,
|
|
52
|
+
|
|
53
|
+
where `I` is an interval of `\RR`.
|
|
54
|
+
|
|
55
|
+
INPUT:
|
|
56
|
+
|
|
57
|
+
- ``parent`` --
|
|
58
|
+
:class:`~sage.manifolds.differentiable.manifold_homset.DifferentiableCurveSet`
|
|
59
|
+
the set of curves `\mathrm{Hom}(I, M)` to which the curve belongs
|
|
60
|
+
- ``coord_expression`` -- (default: ``None``) dictionary (possibly empty)
|
|
61
|
+
of the functions of the curve parameter `t` expressing the curve in
|
|
62
|
+
various charts of `M`, the keys of the dictionary being the charts and
|
|
63
|
+
the values being lists or tuples of `n` symbolic expressions of `t`,
|
|
64
|
+
where `n` is the dimension of `M`
|
|
65
|
+
- ``name`` -- (default: ``None``) string; symbol given to the curve
|
|
66
|
+
- ``latex_name`` -- (default: ``None``) string; LaTeX symbol to denote
|
|
67
|
+
the curve; if none is provided, ``name`` will be used
|
|
68
|
+
- ``is_isomorphism`` -- boolean (default: ``False``); determines whether the
|
|
69
|
+
constructed object is a diffeomorphism; if set to ``True``,
|
|
70
|
+
then `M` must have dimension one
|
|
71
|
+
- ``is_identity`` -- boolean (default: ``False``); determines whether the
|
|
72
|
+
constructed object is the identity map; if set to ``True``,
|
|
73
|
+
then `M` must be the interval `I`
|
|
74
|
+
|
|
75
|
+
EXAMPLES:
|
|
76
|
+
|
|
77
|
+
The lemniscate of Gerono in the 2-dimensional Euclidean plane::
|
|
78
|
+
|
|
79
|
+
sage: M = Manifold(2, 'M')
|
|
80
|
+
sage: X.<x,y> = M.chart()
|
|
81
|
+
sage: t = var('t')
|
|
82
|
+
sage: c = M.curve({X: [sin(t), sin(2*t)/2]}, (t, 0, 2*pi), name='c') ; c
|
|
83
|
+
Curve c in the 2-dimensional differentiable manifold M
|
|
84
|
+
sage: type(c)
|
|
85
|
+
<class 'sage.manifolds.differentiable.manifold_homset.DifferentiableCurveSet_with_category.element_class'>
|
|
86
|
+
|
|
87
|
+
Instead of declaring the parameter `t` as a symbolic variable by means
|
|
88
|
+
of ``var('t')``, it is equivalent to get it as the canonical coordinate
|
|
89
|
+
of the real number line (see
|
|
90
|
+
:class:`~sage.manifolds.differentiable.examples.real_line.RealLine`)::
|
|
91
|
+
|
|
92
|
+
sage: R.<t> = manifolds.RealLine()
|
|
93
|
+
sage: c = M.curve({X: [sin(t), sin(2*t)/2]}, (t, 0, 2*pi), name='c') ; c
|
|
94
|
+
Curve c in the 2-dimensional differentiable manifold M
|
|
95
|
+
|
|
96
|
+
A graphical view of the curve is provided by the method :meth:`plot`::
|
|
97
|
+
|
|
98
|
+
sage: c.plot(aspect_ratio=1) # needs sage.plot
|
|
99
|
+
Graphics object consisting of 1 graphics primitive
|
|
100
|
+
|
|
101
|
+
.. PLOT::
|
|
102
|
+
|
|
103
|
+
M = Manifold(2, 'M')
|
|
104
|
+
X = M.chart('x y')
|
|
105
|
+
t = manifolds.RealLine().canonical_coordinate()
|
|
106
|
+
c = M.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='c')
|
|
107
|
+
g = c.plot(aspect_ratio=1)
|
|
108
|
+
sphinx_plot(g)
|
|
109
|
+
|
|
110
|
+
Curves are considered as (manifold) morphisms from real intervals to
|
|
111
|
+
differentiable manifolds::
|
|
112
|
+
|
|
113
|
+
sage: c.parent()
|
|
114
|
+
Set of Morphisms from Real interval (0, 2*pi) to 2-dimensional
|
|
115
|
+
differentiable manifold M in Category of smooth manifolds over Real
|
|
116
|
+
Field with 53 bits of precision
|
|
117
|
+
sage: I = R.open_interval(0, 2*pi)
|
|
118
|
+
sage: c.parent() is Hom(I, M)
|
|
119
|
+
True
|
|
120
|
+
sage: c.domain()
|
|
121
|
+
Real interval (0, 2*pi)
|
|
122
|
+
sage: c.domain() is I
|
|
123
|
+
True
|
|
124
|
+
sage: c.codomain()
|
|
125
|
+
2-dimensional differentiable manifold M
|
|
126
|
+
|
|
127
|
+
Accordingly, all methods of
|
|
128
|
+
:class:`~sage.manifolds.differentiable.diff_map.DiffMap` are available
|
|
129
|
+
for them. In particular, the method
|
|
130
|
+
:meth:`~sage.manifolds.continuous_map.ContinuousMap.display`
|
|
131
|
+
shows the coordinate representations in various charts of manifold ``M``::
|
|
132
|
+
|
|
133
|
+
sage: c.display()
|
|
134
|
+
c: (0, 2*pi) → M
|
|
135
|
+
t ↦ (x, y) = (sin(t), 1/2*sin(2*t))
|
|
136
|
+
|
|
137
|
+
Another map method is using the usual call syntax, which returns
|
|
138
|
+
the image of a point in the curve's domain::
|
|
139
|
+
|
|
140
|
+
sage: t0 = pi/2
|
|
141
|
+
sage: I(t0)
|
|
142
|
+
Point on the Real number line ℝ
|
|
143
|
+
sage: c(I(t0))
|
|
144
|
+
Point on the 2-dimensional differentiable manifold M
|
|
145
|
+
sage: c(I(t0)).coord(X)
|
|
146
|
+
(1, 0)
|
|
147
|
+
|
|
148
|
+
For curves, the value of the parameter, instead of the corresponding
|
|
149
|
+
point in the real line manifold, can be passed directly::
|
|
150
|
+
|
|
151
|
+
sage: c(t0)
|
|
152
|
+
Point c(1/2*pi) on the 2-dimensional differentiable manifold M
|
|
153
|
+
sage: c(t0).coord(X)
|
|
154
|
+
(1, 0)
|
|
155
|
+
sage: c(t0) == c(I(t0))
|
|
156
|
+
True
|
|
157
|
+
|
|
158
|
+
Instead of a dictionary of coordinate expressions, the curve can be
|
|
159
|
+
defined by a single coordinate expression in a given chart::
|
|
160
|
+
|
|
161
|
+
sage: c = M.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), chart=X, name='c') ; c
|
|
162
|
+
Curve c in the 2-dimensional differentiable manifold M
|
|
163
|
+
sage: c.display()
|
|
164
|
+
c: (0, 2*pi) → M
|
|
165
|
+
t ↦ (x, y) = (sin(t), 1/2*sin(2*t))
|
|
166
|
+
|
|
167
|
+
Since ``X`` is the default chart on ``M``, it can be omitted::
|
|
168
|
+
|
|
169
|
+
sage: c = M.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='c') ; c
|
|
170
|
+
Curve c in the 2-dimensional differentiable manifold M
|
|
171
|
+
sage: c.display()
|
|
172
|
+
c: (0, 2*pi) → M
|
|
173
|
+
t ↦ (x, y) = (sin(t), 1/2*sin(2*t))
|
|
174
|
+
|
|
175
|
+
Note that a curve in `M` can also be created as a differentiable
|
|
176
|
+
map `I \to M`::
|
|
177
|
+
|
|
178
|
+
sage: c1 = I.diff_map(M, coord_functions={X: [sin(t), sin(2*t)/2]},
|
|
179
|
+
....: name='c') ; c1
|
|
180
|
+
Curve c in the 2-dimensional differentiable manifold M
|
|
181
|
+
sage: c1.parent() is c.parent()
|
|
182
|
+
True
|
|
183
|
+
sage: c1 == c
|
|
184
|
+
True
|
|
185
|
+
|
|
186
|
+
LaTeX symbols representing a curve::
|
|
187
|
+
|
|
188
|
+
sage: c = M.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi))
|
|
189
|
+
sage: latex(c)
|
|
190
|
+
\text{Curve in the 2-dimensional differentiable manifold M}
|
|
191
|
+
sage: c = M.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='c')
|
|
192
|
+
sage: latex(c)
|
|
193
|
+
c
|
|
194
|
+
sage: c = M.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='c',
|
|
195
|
+
....: latex_name=r'\gamma')
|
|
196
|
+
sage: latex(c)
|
|
197
|
+
\gamma
|
|
198
|
+
|
|
199
|
+
The curve's tangent vector field (velocity vector)::
|
|
200
|
+
|
|
201
|
+
sage: v = c.tangent_vector_field() ; v
|
|
202
|
+
Vector field c' along the Real interval (0, 2*pi) with values on the
|
|
203
|
+
2-dimensional differentiable manifold M
|
|
204
|
+
sage: v.display()
|
|
205
|
+
c' = cos(t) ∂/∂x + (2*cos(t)^2 - 1) ∂/∂y
|
|
206
|
+
|
|
207
|
+
Plot of the curve and its tangent vector field::
|
|
208
|
+
|
|
209
|
+
sage: show(c.plot(thickness=2, aspect_ratio=1) + # needs sage.plot
|
|
210
|
+
....: v.plot(chart=X, number_values=17, scale=0.5))
|
|
211
|
+
|
|
212
|
+
.. PLOT::
|
|
213
|
+
|
|
214
|
+
M = Manifold(2, 'M')
|
|
215
|
+
X = M.chart('x y')
|
|
216
|
+
t = manifolds.RealLine().canonical_coordinate()
|
|
217
|
+
c = M.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='c')
|
|
218
|
+
v = c.tangent_vector_field()
|
|
219
|
+
g = c.plot(thickness=2, aspect_ratio=1) + v.plot(chart=X, number_values=17, scale=0.5)
|
|
220
|
+
sphinx_plot(g)
|
|
221
|
+
|
|
222
|
+
Value of the tangent vector field at `t = \pi`::
|
|
223
|
+
|
|
224
|
+
sage: v.at(R(pi))
|
|
225
|
+
Tangent vector c' at Point on the 2-dimensional differentiable
|
|
226
|
+
manifold M
|
|
227
|
+
sage: v.at(R(pi)) in M.tangent_space(c(R(pi)))
|
|
228
|
+
True
|
|
229
|
+
sage: v.at(R(pi)).display()
|
|
230
|
+
c' = -∂/∂x + ∂/∂y
|
|
231
|
+
|
|
232
|
+
Curves `\RR \to \RR` can be composed: the operator `\circ` is
|
|
233
|
+
given by ``*``::
|
|
234
|
+
|
|
235
|
+
sage: f = R.curve(t^2, (t,-oo,+oo))
|
|
236
|
+
sage: g = R.curve(cos(t), (t,-oo,+oo))
|
|
237
|
+
sage: s = g*f ; s
|
|
238
|
+
Differentiable map from the Real number line ℝ to itself
|
|
239
|
+
sage: s.display()
|
|
240
|
+
ℝ → ℝ
|
|
241
|
+
t ↦ cos(t^2)
|
|
242
|
+
sage: s = f*g ; s
|
|
243
|
+
Differentiable map from the Real number line ℝ to itself
|
|
244
|
+
sage: s.display()
|
|
245
|
+
ℝ → ℝ
|
|
246
|
+
t ↦ cos(t)^2
|
|
247
|
+
|
|
248
|
+
.. RUBRIC:: Curvature and torsion of a curve in a Riemannian manifold
|
|
249
|
+
|
|
250
|
+
Let us consider a helix `C` in the Euclidean space `\mathbb{E}^3`
|
|
251
|
+
parametrized by its arc length `s`::
|
|
252
|
+
|
|
253
|
+
sage: E.<x,y,z> = EuclideanSpace()
|
|
254
|
+
sage: R.<s> = manifolds.RealLine()
|
|
255
|
+
sage: C = E.curve((2*cos(s/3), 2*sin(s/3), sqrt(5)*s/3), (s, 0, 6*pi),
|
|
256
|
+
....: name='C')
|
|
257
|
+
|
|
258
|
+
Its tangent vector field is::
|
|
259
|
+
|
|
260
|
+
sage: T = C.tangent_vector_field()
|
|
261
|
+
sage: T.display()
|
|
262
|
+
C' = -2/3*sin(1/3*s) e_x + 2/3*cos(1/3*s) e_y + 1/3*sqrt(5) e_z
|
|
263
|
+
|
|
264
|
+
Since `C` is parametrized by its arc length `s`, `T` is a unit vector (with
|
|
265
|
+
respect to the Euclidean metric of `\mathbb{E}^3`)::
|
|
266
|
+
|
|
267
|
+
sage: norm(T)
|
|
268
|
+
Scalar field |C'| on the Real interval (0, 6*pi)
|
|
269
|
+
sage: norm(T).display()
|
|
270
|
+
|C'|: (0, 6*pi) → ℝ
|
|
271
|
+
s ↦ 1
|
|
272
|
+
|
|
273
|
+
Vector fields along `C` are defined by the method
|
|
274
|
+
:meth:`~sage.manifolds.differentiable.manifold.DifferentiableManifold.vector_field`
|
|
275
|
+
of the domain of `C` with the keyword argument ``dest_map`` set to `C`. For
|
|
276
|
+
instance the derivative vector `T'=\mathrm{d}T/\mathrm{d}s` is::
|
|
277
|
+
|
|
278
|
+
sage: I = C.domain(); I
|
|
279
|
+
Real interval (0, 6*pi)
|
|
280
|
+
sage: Tp = I.vector_field([diff(T[i], s) for i in E.irange()], dest_map=C,
|
|
281
|
+
....: name="T'")
|
|
282
|
+
sage: Tp.display()
|
|
283
|
+
T' = -2/9*cos(1/3*s) e_x - 2/9*sin(1/3*s) e_y
|
|
284
|
+
|
|
285
|
+
The norm of `T'` is the curvature of the helix::
|
|
286
|
+
|
|
287
|
+
sage: kappa = norm(Tp)
|
|
288
|
+
sage: kappa
|
|
289
|
+
Scalar field |T'| on the Real interval (0, 6*pi)
|
|
290
|
+
sage: kappa.expr()
|
|
291
|
+
2/9
|
|
292
|
+
|
|
293
|
+
The unit normal vector along `C` is::
|
|
294
|
+
|
|
295
|
+
sage: N = Tp / kappa
|
|
296
|
+
sage: N.display()
|
|
297
|
+
-cos(1/3*s) e_x - sin(1/3*s) e_y
|
|
298
|
+
|
|
299
|
+
while the binormal vector along `C` is `B = T \times N`::
|
|
300
|
+
|
|
301
|
+
sage: B = T.cross_product(N)
|
|
302
|
+
sage: B
|
|
303
|
+
Vector field along the Real interval (0, 6*pi) with values on the
|
|
304
|
+
Euclidean space E^3
|
|
305
|
+
sage: B.display()
|
|
306
|
+
1/3*sqrt(5)*sin(1/3*s) e_x - 1/3*sqrt(5)*cos(1/3*s) e_y + 2/3 e_z
|
|
307
|
+
|
|
308
|
+
The three vector fields `(T, N, B)` form the **Frenet-Serret frame** along
|
|
309
|
+
`C`::
|
|
310
|
+
|
|
311
|
+
sage: FS = I.vector_frame(('T', 'N', 'B'), (T, N, B),
|
|
312
|
+
....: symbol_dual=('t', 'n', 'b'))
|
|
313
|
+
sage: FS
|
|
314
|
+
Vector frame ((0, 6*pi), (T,N,B)) with values on the Euclidean space E^3
|
|
315
|
+
|
|
316
|
+
The Frenet-Serret frame is orthonormal::
|
|
317
|
+
|
|
318
|
+
sage: matrix([[u.dot(v).expr() for v in FS] for u in FS])
|
|
319
|
+
[1 0 0]
|
|
320
|
+
[0 1 0]
|
|
321
|
+
[0 0 1]
|
|
322
|
+
|
|
323
|
+
The derivative vectors `N'` and `B'`::
|
|
324
|
+
|
|
325
|
+
sage: Np = I.vector_field([diff(N[i], s) for i in E.irange()],
|
|
326
|
+
....: dest_map=C, name="N'")
|
|
327
|
+
sage: Np.display()
|
|
328
|
+
N' = 1/3*sin(1/3*s) e_x - 1/3*cos(1/3*s) e_y
|
|
329
|
+
sage: Bp = I.vector_field([diff(B[i], s) for i in E.irange()],
|
|
330
|
+
....: dest_map=C, name="B'")
|
|
331
|
+
sage: Bp.display()
|
|
332
|
+
B' = 1/9*sqrt(5)*cos(1/3*s) e_x + 1/9*sqrt(5)*sin(1/3*s) e_y
|
|
333
|
+
|
|
334
|
+
The Frenet-Serret formulas::
|
|
335
|
+
|
|
336
|
+
sage: for v in (Tp, Np, Bp):
|
|
337
|
+
....: v.display(FS)
|
|
338
|
+
....:
|
|
339
|
+
T' = 2/9 N
|
|
340
|
+
N' = -2/9 T + 1/9*sqrt(5) B
|
|
341
|
+
B' = -1/9*sqrt(5) N
|
|
342
|
+
|
|
343
|
+
The torsion of `C` is obtained as the third component of `N'` in the
|
|
344
|
+
Frenet-Serret frame::
|
|
345
|
+
|
|
346
|
+
sage: tau = Np[FS, 3]
|
|
347
|
+
sage: tau
|
|
348
|
+
1/9*sqrt(5)
|
|
349
|
+
"""
|
|
350
|
+
def __init__(self, parent, coord_expression=None, name=None,
|
|
351
|
+
latex_name=None, is_isomorphism=False, is_identity=False):
|
|
352
|
+
r"""
|
|
353
|
+
Construct a curve.
|
|
354
|
+
|
|
355
|
+
TESTS::
|
|
356
|
+
|
|
357
|
+
sage: M = Manifold(2, 'M')
|
|
358
|
+
sage: X.<x,y> = M.chart()
|
|
359
|
+
sage: R.<t> = manifolds.RealLine()
|
|
360
|
+
sage: I = R.open_interval(0, 2*pi)
|
|
361
|
+
sage: c = Hom(I,M)({X: (cos(t), sin(2*t))}, name='c') ; c
|
|
362
|
+
Curve c in the 2-dimensional differentiable manifold M
|
|
363
|
+
sage: TestSuite(c).run()
|
|
364
|
+
|
|
365
|
+
The identity of interval ``I``::
|
|
366
|
+
|
|
367
|
+
sage: c = Hom(I,I)({}, is_identity=True) ; c
|
|
368
|
+
Identity map Id_(0, 2*pi) of the Real interval (0, 2*pi)
|
|
369
|
+
sage: TestSuite(c).run()
|
|
370
|
+
"""
|
|
371
|
+
if coord_expression is None:
|
|
372
|
+
coord_functions = None
|
|
373
|
+
else:
|
|
374
|
+
if not isinstance(coord_expression, dict):
|
|
375
|
+
raise TypeError("{} is not a dictionary".format(
|
|
376
|
+
coord_expression))
|
|
377
|
+
param_chart = parent.domain().canonical_chart()
|
|
378
|
+
coord_functions = {}
|
|
379
|
+
for chart, expr in coord_expression.items():
|
|
380
|
+
if isinstance(chart, tuple):
|
|
381
|
+
# a pair of charts is passed:
|
|
382
|
+
coord_functions[chart] = expr
|
|
383
|
+
else:
|
|
384
|
+
coord_functions[(param_chart, chart)] = expr
|
|
385
|
+
DiffMap.__init__(self, parent, coord_functions=coord_functions,
|
|
386
|
+
name=name, latex_name=latex_name,
|
|
387
|
+
is_isomorphism=is_isomorphism,
|
|
388
|
+
is_identity=is_identity)
|
|
389
|
+
|
|
390
|
+
def _repr_(self):
|
|
391
|
+
r"""
|
|
392
|
+
Return a string representation of ``self``.
|
|
393
|
+
|
|
394
|
+
TESTS::
|
|
395
|
+
|
|
396
|
+
sage: M = Manifold(2, 'M')
|
|
397
|
+
sage: X.<x,y> = M.chart()
|
|
398
|
+
sage: R.<t> = manifolds.RealLine()
|
|
399
|
+
sage: M.curve([cos(t), sin(2*t)], (t, 0, 2*pi))
|
|
400
|
+
Curve in the 2-dimensional differentiable manifold M
|
|
401
|
+
sage: M.curve([cos(t), sin(2*t)], (t, 0, 2*pi), name='c')
|
|
402
|
+
Curve c in the 2-dimensional differentiable manifold M
|
|
403
|
+
"""
|
|
404
|
+
if self._codomain._dim == 1:
|
|
405
|
+
return DiffMap._repr_(self)
|
|
406
|
+
description = "Curve "
|
|
407
|
+
if self._name is not None:
|
|
408
|
+
description += self._name + " "
|
|
409
|
+
description += "in the {}".format(self._codomain)
|
|
410
|
+
return description
|
|
411
|
+
|
|
412
|
+
def __reduce__(self):
|
|
413
|
+
r"""
|
|
414
|
+
Reduction function for the pickle protocole.
|
|
415
|
+
|
|
416
|
+
TESTS::
|
|
417
|
+
|
|
418
|
+
sage: M = Manifold(2, 'M')
|
|
419
|
+
sage: X.<x,y> = M.chart()
|
|
420
|
+
sage: R.<t> = manifolds.RealLine()
|
|
421
|
+
sage: c = M.curve([cos(t), sin(2*t)], (t, 0, 2*pi))
|
|
422
|
+
sage: c.__reduce__()
|
|
423
|
+
(<class 'sage.manifolds.differentiable.manifold_homset.DifferentiableCurveSet_with_category.element_class'>,
|
|
424
|
+
(Set of Morphisms from Real interval (0, 2*pi) to 2-dimensional
|
|
425
|
+
differentiable manifold M in Category of smooth manifolds over
|
|
426
|
+
Real Field with 53 bits of precision,
|
|
427
|
+
None,
|
|
428
|
+
None,
|
|
429
|
+
None,
|
|
430
|
+
False,
|
|
431
|
+
False))
|
|
432
|
+
|
|
433
|
+
Test of pickling::
|
|
434
|
+
|
|
435
|
+
sage: loads(dumps(c))
|
|
436
|
+
Curve in the 2-dimensional differentiable manifold M
|
|
437
|
+
"""
|
|
438
|
+
return (type(self), (self.parent(), None, self._name, self._latex_name,
|
|
439
|
+
self._is_isomorphism, self._is_identity))
|
|
440
|
+
|
|
441
|
+
def coord_expr(self, chart=None):
|
|
442
|
+
r"""
|
|
443
|
+
Return the coordinate functions expressing the curve in a given chart.
|
|
444
|
+
|
|
445
|
+
INPUT:
|
|
446
|
+
|
|
447
|
+
- ``chart`` -- (default: ``None``) chart on the curve's codomain; if
|
|
448
|
+
``None``, the codomain's default chart is assumed
|
|
449
|
+
|
|
450
|
+
OUTPUT: symbolic expression representing the curve in the above chart
|
|
451
|
+
|
|
452
|
+
EXAMPLES:
|
|
453
|
+
|
|
454
|
+
Cartesian and polar expression of a curve in the Euclidean plane::
|
|
455
|
+
|
|
456
|
+
sage: M = Manifold(2, 'R^2', r'\RR^2') # the Euclidean plane R^2
|
|
457
|
+
sage: c_xy.<x,y> = M.chart() # Cartesian coordinate on R^2
|
|
458
|
+
sage: U = M.open_subset('U', coord_def={c_xy: (y!=0, x<0)}) # the complement of the segment y=0 and x>0
|
|
459
|
+
sage: c_cart = c_xy.restrict(U) # Cartesian coordinates on U
|
|
460
|
+
sage: c_spher.<r,ph> = U.chart(r'r:(0,+oo) ph:(0,2*pi):\phi') # spherical coordinates on U
|
|
461
|
+
|
|
462
|
+
Links between spherical coordinates and Cartesian ones::
|
|
463
|
+
|
|
464
|
+
sage: ch_cart_spher = c_cart.transition_map(c_spher, [sqrt(x*x+y*y), atan2(y,x)])
|
|
465
|
+
sage: ch_cart_spher.set_inverse(r*cos(ph), r*sin(ph))
|
|
466
|
+
Check of the inverse coordinate transformation:
|
|
467
|
+
x == x *passed*
|
|
468
|
+
y == y *passed*
|
|
469
|
+
r == r *passed*
|
|
470
|
+
ph == arctan2(r*sin(ph), r*cos(ph)) **failed**
|
|
471
|
+
NB: a failed report can reflect a mere lack of simplification.
|
|
472
|
+
sage: R.<t> = manifolds.RealLine()
|
|
473
|
+
sage: c = U.curve({c_spher: (1,t)}, (t, 0, 2*pi), name='c')
|
|
474
|
+
sage: c.coord_expr(c_spher)
|
|
475
|
+
(1, t)
|
|
476
|
+
sage: c.coord_expr(c_cart)
|
|
477
|
+
(cos(t), sin(t))
|
|
478
|
+
|
|
479
|
+
Since ``c_cart`` is the default chart on ``U``, it can be omitted::
|
|
480
|
+
|
|
481
|
+
sage: c.coord_expr()
|
|
482
|
+
(cos(t), sin(t))
|
|
483
|
+
|
|
484
|
+
Cartesian expression of a cardioid::
|
|
485
|
+
|
|
486
|
+
sage: c = U.curve({c_spher: (2*(1+cos(t)), t)}, (t, 0, 2*pi), name='c')
|
|
487
|
+
sage: c.coord_expr(c_cart)
|
|
488
|
+
(2*cos(t)^2 + 2*cos(t), 2*(cos(t) + 1)*sin(t))
|
|
489
|
+
"""
|
|
490
|
+
return self.expr(chart1=self._domain.canonical_chart(), chart2=chart)
|
|
491
|
+
|
|
492
|
+
def __call__(self, t, simplify=True):
|
|
493
|
+
r"""
|
|
494
|
+
Image for a given value of the curve parameter.
|
|
495
|
+
|
|
496
|
+
This is a redefinition of :meth:`sage.categories.map.Map.__call__`
|
|
497
|
+
to allow for the direct call with some value of the parameter
|
|
498
|
+
(numerical value or symbolic expression) instead of the element
|
|
499
|
+
(ManifoldPoint) of the domain corresponding to that value.
|
|
500
|
+
|
|
501
|
+
EXAMPLES:
|
|
502
|
+
|
|
503
|
+
Points on circle in the Euclidean plane::
|
|
504
|
+
|
|
505
|
+
sage: M = Manifold(2, 'M')
|
|
506
|
+
sage: X.<x,y> = M.chart()
|
|
507
|
+
sage: R.<t> = manifolds.RealLine()
|
|
508
|
+
sage: c = M.curve([cos(t), sin(t)], (t, 0, 2*pi), name='c')
|
|
509
|
+
sage: c(0)
|
|
510
|
+
Point c(0) on the 2-dimensional differentiable manifold M
|
|
511
|
+
sage: c(0) in M
|
|
512
|
+
True
|
|
513
|
+
sage: c(0).coord(X)
|
|
514
|
+
(1, 0)
|
|
515
|
+
sage: c(pi/4).coord(X)
|
|
516
|
+
(1/2*sqrt(2), 1/2*sqrt(2))
|
|
517
|
+
sage: c(t)
|
|
518
|
+
Point c(t) on the 2-dimensional differentiable manifold M
|
|
519
|
+
sage: c(t).coord(X)
|
|
520
|
+
(cos(t), sin(t))
|
|
521
|
+
"""
|
|
522
|
+
# Case of a point in the domain:
|
|
523
|
+
if isinstance(t, ManifoldPoint):
|
|
524
|
+
return DiffMap.__call__(self, t)
|
|
525
|
+
|
|
526
|
+
# Case of a value of the canonical coordinate in the domain:
|
|
527
|
+
codom = self._codomain
|
|
528
|
+
canon_chart = self._domain._canon_chart
|
|
529
|
+
canon_coord = canon_chart._xx[0]
|
|
530
|
+
if (canon_chart, codom._def_chart) in self._coord_expression:
|
|
531
|
+
chart_pair = (canon_chart, codom._def_chart)
|
|
532
|
+
else:
|
|
533
|
+
chart_pair = next(iter(self._coord_expression.keys()))
|
|
534
|
+
# a chart is picked at random
|
|
535
|
+
coord_functions = self._coord_expression[chart_pair]._functions
|
|
536
|
+
n = codom._dim
|
|
537
|
+
dict_subs = {canon_coord: t}
|
|
538
|
+
coords = [coord_functions[i].expr().substitute(dict_subs)
|
|
539
|
+
for i in range(n)]
|
|
540
|
+
if simplify:
|
|
541
|
+
coords = [chart_pair[0].simplify(coords[i]) for i in range(n)]
|
|
542
|
+
if self._name is not None:
|
|
543
|
+
name = "{}({})".format(self._name, t)
|
|
544
|
+
else:
|
|
545
|
+
name = None
|
|
546
|
+
if self._latex_name is not None:
|
|
547
|
+
latex_name = r"{}\left({}\right)".format(self._latex_name, latex(t))
|
|
548
|
+
else:
|
|
549
|
+
latex_name = None
|
|
550
|
+
return codom.element_class(codom, coords=coords, chart=chart_pair[1],
|
|
551
|
+
name=name, latex_name=latex_name,
|
|
552
|
+
check_coords=False)
|
|
553
|
+
|
|
554
|
+
def tangent_vector_field(self, name=None, latex_name=None):
|
|
555
|
+
r"""
|
|
556
|
+
Return the tangent vector field to the curve (velocity vector).
|
|
557
|
+
|
|
558
|
+
INPUT:
|
|
559
|
+
|
|
560
|
+
- ``name`` -- (default: ``None``) string; symbol given to the tangent
|
|
561
|
+
vector field; if none is provided, the primed curve symbol (if any)
|
|
562
|
+
will be used
|
|
563
|
+
- ``latex_name`` -- (default: ``None``) string; LaTeX symbol to denote
|
|
564
|
+
the tangent vector field; if ``None`` then (i) if ``name`` is
|
|
565
|
+
``None`` as well, the primed curve LaTeX symbol (if any) will be
|
|
566
|
+
used or (ii) if ``name`` is not ``None``, ``name`` will be used
|
|
567
|
+
|
|
568
|
+
OUTPUT:
|
|
569
|
+
|
|
570
|
+
- the tangent vector field, as an instance of
|
|
571
|
+
:class:`~sage.manifolds.differentiable.vectorfield.VectorField`
|
|
572
|
+
|
|
573
|
+
EXAMPLES:
|
|
574
|
+
|
|
575
|
+
Tangent vector field to a circle curve in `\RR^2`::
|
|
576
|
+
|
|
577
|
+
sage: M = Manifold(2, 'R^2')
|
|
578
|
+
sage: X.<x,y> = M.chart()
|
|
579
|
+
sage: R.<t> = manifolds.RealLine()
|
|
580
|
+
sage: c = M.curve([cos(t), sin(t)], (t, 0, 2*pi), name='c')
|
|
581
|
+
sage: v = c.tangent_vector_field() ; v
|
|
582
|
+
Vector field c' along the Real interval (0, 2*pi) with values on
|
|
583
|
+
the 2-dimensional differentiable manifold R^2
|
|
584
|
+
sage: v.display()
|
|
585
|
+
c' = -sin(t) ∂/∂x + cos(t) ∂/∂y
|
|
586
|
+
sage: latex(v)
|
|
587
|
+
{c'}
|
|
588
|
+
sage: v.parent()
|
|
589
|
+
Free module X((0, 2*pi),c) of vector fields along the Real interval
|
|
590
|
+
(0, 2*pi) mapped into the 2-dimensional differentiable manifold R^2
|
|
591
|
+
|
|
592
|
+
Value of the tangent vector field for some specific value of the
|
|
593
|
+
curve parameter (`t = \pi`)::
|
|
594
|
+
|
|
595
|
+
sage: R(pi) in c.domain() # pi in (0, 2*pi)
|
|
596
|
+
True
|
|
597
|
+
sage: vp = v.at(R(pi)) ; vp
|
|
598
|
+
Tangent vector c' at Point on the 2-dimensional differentiable
|
|
599
|
+
manifold R^2
|
|
600
|
+
sage: vp.parent() is M.tangent_space(c(R(pi)))
|
|
601
|
+
True
|
|
602
|
+
sage: vp.display()
|
|
603
|
+
c' = -∂/∂y
|
|
604
|
+
|
|
605
|
+
Tangent vector field to a curve in a non-parallelizable manifold (the
|
|
606
|
+
2-sphere `S^2`): first, we introduce the 2-sphere::
|
|
607
|
+
|
|
608
|
+
sage: M = Manifold(2, 'M') # the 2-dimensional sphere S^2
|
|
609
|
+
sage: U = M.open_subset('U') # complement of the North pole
|
|
610
|
+
sage: c_xy.<x,y> = U.chart() # stereographic coordinates from the North pole
|
|
611
|
+
sage: V = M.open_subset('V') # complement of the South pole
|
|
612
|
+
sage: c_uv.<u,v> = V.chart() # stereographic coordinates from the South pole
|
|
613
|
+
sage: M.declare_union(U,V) # S^2 is the union of U and V
|
|
614
|
+
sage: xy_to_uv = c_xy.transition_map(c_uv, (x/(x^2+y^2), y/(x^2+y^2)),
|
|
615
|
+
....: intersection_name='W', restrictions1= x^2+y^2!=0,
|
|
616
|
+
....: restrictions2= u^2+v^2!=0)
|
|
617
|
+
sage: uv_to_xy = xy_to_uv.inverse()
|
|
618
|
+
sage: W = U.intersection(V)
|
|
619
|
+
sage: A = W.open_subset('A', coord_def={c_xy.restrict(W): (y!=0, x<0)})
|
|
620
|
+
sage: c_spher.<th,ph> = A.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi') # spherical coordinates
|
|
621
|
+
sage: spher_to_xy = c_spher.transition_map(c_xy.restrict(A),
|
|
622
|
+
....: (sin(th)*cos(ph)/(1-cos(th)), sin(th)*sin(ph)/(1-cos(th))) )
|
|
623
|
+
sage: spher_to_xy.set_inverse(2*atan(1/sqrt(x^2+y^2)), atan2(y, x), check=False)
|
|
624
|
+
|
|
625
|
+
Then we define a curve (a loxodrome) by its expression in terms of
|
|
626
|
+
spherical coordinates and evaluate the tangent vector field::
|
|
627
|
+
|
|
628
|
+
sage: R.<t> = manifolds.RealLine()
|
|
629
|
+
sage: c = M.curve({c_spher: [2*atan(exp(-t/10)), t]}, (t, -oo, +oo),
|
|
630
|
+
....: name='c') ; c
|
|
631
|
+
Curve c in the 2-dimensional differentiable manifold M
|
|
632
|
+
sage: vc = c.tangent_vector_field() ; vc
|
|
633
|
+
Vector field c' along the Real number line ℝ with values on
|
|
634
|
+
the 2-dimensional differentiable manifold M
|
|
635
|
+
sage: vc.parent()
|
|
636
|
+
Module X(ℝ,c) of vector fields along the Real number line ℝ
|
|
637
|
+
mapped into the 2-dimensional differentiable manifold M
|
|
638
|
+
sage: vc.display(c_spher.frame().along(c.restrict(R,A)))
|
|
639
|
+
c' = -1/5*e^(1/10*t)/(e^(1/5*t) + 1) ∂/∂th + ∂/∂ph
|
|
640
|
+
"""
|
|
641
|
+
vmodule = self._domain.vector_field_module(dest_map=self)
|
|
642
|
+
if latex_name is None:
|
|
643
|
+
if name is None:
|
|
644
|
+
if self._latex_name is not None:
|
|
645
|
+
latex_name = r"{%s'}" % (self._latex_name)
|
|
646
|
+
else:
|
|
647
|
+
latex_name = name
|
|
648
|
+
if name is None and self._name is not None:
|
|
649
|
+
name = self._name + "'"
|
|
650
|
+
resu = vmodule.element_class(vmodule, name=name, latex_name=latex_name)
|
|
651
|
+
canon_chart = self._domain.canonical_chart()
|
|
652
|
+
codom = self._codomain
|
|
653
|
+
dim = codom._dim
|
|
654
|
+
codom_top_charts = codom._top_charts
|
|
655
|
+
for chart in codom_top_charts:
|
|
656
|
+
try:
|
|
657
|
+
jacob = self.differential_functions(canon_chart, chart)
|
|
658
|
+
restrict = self.restrict(canon_chart.domain(),
|
|
659
|
+
subcodomain=chart.domain())
|
|
660
|
+
fmodule = restrict._domain.vector_field_module(dest_map=restrict)
|
|
661
|
+
frame = fmodule.basis(from_frame=chart.frame())
|
|
662
|
+
resu_rest = resu.restrict(canon_chart.domain(), dest_map=restrict)
|
|
663
|
+
resu_rest.add_comp(frame)[:, canon_chart] = [jacob[i][0]
|
|
664
|
+
for i in range(dim)]
|
|
665
|
+
except ValueError:
|
|
666
|
+
pass
|
|
667
|
+
return resu
|
|
668
|
+
|
|
669
|
+
@options(thickness=1, plot_points=75, max_range=8, aspect_ratio='automatic')
|
|
670
|
+
def plot(self, chart=None, ambient_coords=None, mapping=None, prange=None,
|
|
671
|
+
include_end_point=(True, True), end_point_offset=(0.001, 0.001),
|
|
672
|
+
parameters=None, color='red', style='-', label_axes=True, **kwds):
|
|
673
|
+
r"""
|
|
674
|
+
Plot the current curve in a Cartesian graph based on the
|
|
675
|
+
coordinates of some ambient chart.
|
|
676
|
+
|
|
677
|
+
The curve is drawn in terms of two (2D graphics) or three (3D graphics)
|
|
678
|
+
coordinates of a given chart, called hereafter the *ambient chart*.
|
|
679
|
+
The ambient chart's domain must overlap with the curve's codomain or
|
|
680
|
+
with the codomain of the composite curve `\Phi\circ c`, where `c` is
|
|
681
|
+
the current curve and `\Phi` some manifold differential map (argument
|
|
682
|
+
``mapping`` below).
|
|
683
|
+
|
|
684
|
+
INPUT:
|
|
685
|
+
|
|
686
|
+
- ``chart`` -- (default: ``None``) the ambient chart (see above);
|
|
687
|
+
if ``None``, the default chart of the codomain of the curve (or of
|
|
688
|
+
the curve composed with `\Phi`) is used
|
|
689
|
+
|
|
690
|
+
- ``ambient_coords`` -- (default: ``None``) tuple containing the 2
|
|
691
|
+
or 3 coordinates of the ambient chart in terms of which the plot
|
|
692
|
+
is performed; if ``None``, all the coordinates of the ambient chart
|
|
693
|
+
are considered
|
|
694
|
+
|
|
695
|
+
- ``mapping`` -- (default: ``None``) differentiable mapping `\Phi`
|
|
696
|
+
(instance of
|
|
697
|
+
:class:`~sage.manifolds.differentiable.diff_map.DiffMap`)
|
|
698
|
+
providing the link between the curve and the ambient chart ``chart``
|
|
699
|
+
(cf. above); if ``None``, the ambient chart is supposed to be defined
|
|
700
|
+
on the codomain of the curve.
|
|
701
|
+
|
|
702
|
+
- ``prange`` -- (default: ``None``) range of the curve parameter for
|
|
703
|
+
the plot; if ``None``, the entire parameter range declared during the
|
|
704
|
+
curve construction is considered (with -Infinity
|
|
705
|
+
replaced by ``-max_range`` and +Infinity by ``max_range``)
|
|
706
|
+
|
|
707
|
+
- ``include_end_point`` -- (default: ``(True, True)``) determines
|
|
708
|
+
whether the end points of ``prange`` are included in the plot
|
|
709
|
+
|
|
710
|
+
- ``end_point_offset`` -- (default: ``(0.001, 0.001)``) offsets from
|
|
711
|
+
the end points when they are not included in the plot: if
|
|
712
|
+
``include_end_point[0] == False``, the minimal value of the curve
|
|
713
|
+
parameter used for the plot is ``prange[0] + end_point_offset[0]``,
|
|
714
|
+
while if ``include_end_point[1] == False``, the maximal value is
|
|
715
|
+
``prange[1] - end_point_offset[1]``.
|
|
716
|
+
|
|
717
|
+
- ``max_range`` -- (default: 8) numerical value substituted to
|
|
718
|
+
+Infinity if the latter is the upper bound of the parameter range;
|
|
719
|
+
similarly ``-max_range`` is the numerical valued substituted for
|
|
720
|
+
-Infinity
|
|
721
|
+
|
|
722
|
+
- ``parameters`` -- (default: ``None``) dictionary giving the numerical
|
|
723
|
+
values of the parameters that may appear in the coordinate expression
|
|
724
|
+
of the curve
|
|
725
|
+
|
|
726
|
+
- ``color`` -- (default: ``'red'``) color of the drawn curve
|
|
727
|
+
|
|
728
|
+
- ``style`` -- (default: ``'-'``) color of the drawn curve; NB: ``style``
|
|
729
|
+
is effective only for 2D plots
|
|
730
|
+
|
|
731
|
+
- ``thickness`` -- (default: 1) thickness of the drawn curve
|
|
732
|
+
|
|
733
|
+
- ``plot_points`` -- (default: 75) number of points to plot the curve
|
|
734
|
+
|
|
735
|
+
- ``label_axes`` -- boolean (default: ``True``); determining whether the
|
|
736
|
+
labels of the coordinate axes of ``chart`` shall be added to the
|
|
737
|
+
graph; can be set to ``False`` if the graph is 3D and must be
|
|
738
|
+
superposed with another graph.
|
|
739
|
+
|
|
740
|
+
- ``aspect_ratio`` -- (default: ``'automatic'``) aspect ratio of the
|
|
741
|
+
plot; the default value (``'automatic'``) applies only for 2D plots;
|
|
742
|
+
for 3D plots, the default value is ``1`` instead
|
|
743
|
+
|
|
744
|
+
OUTPUT:
|
|
745
|
+
|
|
746
|
+
- a graphic object, either an instance of
|
|
747
|
+
:class:`~sage.plot.graphics.Graphics` for a 2D plot (i.e. based on
|
|
748
|
+
2 coordinates of ``chart``) or an instance of
|
|
749
|
+
:class:`~sage.plot.plot3d.base.Graphics3d` for a 3D plot (i.e.
|
|
750
|
+
based on 3 coordinates of ``chart``)
|
|
751
|
+
|
|
752
|
+
EXAMPLES:
|
|
753
|
+
|
|
754
|
+
Plot of the lemniscate of Gerono::
|
|
755
|
+
|
|
756
|
+
sage: R2 = Manifold(2, 'R^2')
|
|
757
|
+
sage: X.<x,y> = R2.chart()
|
|
758
|
+
sage: R.<t> = manifolds.RealLine()
|
|
759
|
+
sage: c = R2.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='c')
|
|
760
|
+
sage: c.plot() # 2D plot # needs sage.plot
|
|
761
|
+
Graphics object consisting of 1 graphics primitive
|
|
762
|
+
|
|
763
|
+
.. PLOT::
|
|
764
|
+
|
|
765
|
+
R2 = Manifold(2, 'R^2')
|
|
766
|
+
X = R2.chart('x y')
|
|
767
|
+
t = manifolds.RealLine().canonical_coordinate()
|
|
768
|
+
c = R2.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='c')
|
|
769
|
+
g = c.plot()
|
|
770
|
+
sphinx_plot(g)
|
|
771
|
+
|
|
772
|
+
Plot for a subinterval of the curve's domain::
|
|
773
|
+
|
|
774
|
+
sage: c.plot(prange=(0,pi)) # needs sage.plot
|
|
775
|
+
Graphics object consisting of 1 graphics primitive
|
|
776
|
+
|
|
777
|
+
.. PLOT::
|
|
778
|
+
|
|
779
|
+
R2 = Manifold(2, 'R^2')
|
|
780
|
+
X = R2.chart('x y')
|
|
781
|
+
t = manifolds.RealLine().canonical_coordinate()
|
|
782
|
+
c = R2.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='c')
|
|
783
|
+
g = c.plot(prange=(0,pi))
|
|
784
|
+
sphinx_plot(g)
|
|
785
|
+
|
|
786
|
+
Plot with various options::
|
|
787
|
+
|
|
788
|
+
sage: c.plot(color='green', style=':', thickness=3, aspect_ratio=1) # needs sage.plot
|
|
789
|
+
Graphics object consisting of 1 graphics primitive
|
|
790
|
+
|
|
791
|
+
.. PLOT::
|
|
792
|
+
|
|
793
|
+
R2 = Manifold(2, 'R^2')
|
|
794
|
+
X = R2.chart('x y')
|
|
795
|
+
t = manifolds.RealLine().canonical_coordinate()
|
|
796
|
+
c = R2.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='c')
|
|
797
|
+
g = c.plot(color='green', style=':', thickness=3, aspect_ratio=1)
|
|
798
|
+
sphinx_plot(g)
|
|
799
|
+
|
|
800
|
+
Cardioid defined in terms of polar coordinates and plotted with respect
|
|
801
|
+
to Cartesian coordinates, as an example of use of the optional argument
|
|
802
|
+
``chart``::
|
|
803
|
+
|
|
804
|
+
sage: E.<r,ph> = EuclideanSpace(coordinates='polar')
|
|
805
|
+
sage: c = E.curve((1 + cos(ph), ph), (ph, 0, 2*pi))
|
|
806
|
+
sage: c.plot(chart=E.cartesian_coordinates(), aspect_ratio=1) # needs sage.plot
|
|
807
|
+
Graphics object consisting of 1 graphics primitive
|
|
808
|
+
|
|
809
|
+
.. PLOT::
|
|
810
|
+
|
|
811
|
+
E = EuclideanSpace(2, coordinates='polar')
|
|
812
|
+
r, ph = E.polar_coordinates()[:]
|
|
813
|
+
c = E.curve((1 + cos(ph), ph), (ph, 0, 2*pi))
|
|
814
|
+
g = c.plot(chart=E.cartesian_coordinates(), aspect_ratio=1)
|
|
815
|
+
sphinx_plot(g)
|
|
816
|
+
|
|
817
|
+
Plot via a mapping to another manifold: loxodrome of a sphere viewed
|
|
818
|
+
in `\RR^3`::
|
|
819
|
+
|
|
820
|
+
sage: S2 = Manifold(2, 'S^2')
|
|
821
|
+
sage: U = S2.open_subset('U')
|
|
822
|
+
sage: XS.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
|
|
823
|
+
sage: R3 = Manifold(3, 'R^3')
|
|
824
|
+
sage: X3.<x,y,z> = R3.chart()
|
|
825
|
+
sage: F = S2.diff_map(R3, {(XS, X3): [sin(th)*cos(ph),
|
|
826
|
+
....: sin(th)*sin(ph), cos(th)]}, name='F')
|
|
827
|
+
sage: F.display()
|
|
828
|
+
F: S^2 → R^3
|
|
829
|
+
on U: (th, ph) ↦ (x, y, z) = (cos(ph)*sin(th), sin(ph)*sin(th), cos(th))
|
|
830
|
+
sage: c = S2.curve([2*atan(exp(-t/10)), t], (t, -oo, +oo), name='c')
|
|
831
|
+
sage: graph_c = c.plot(mapping=F, max_range=40, # needs sage.plot
|
|
832
|
+
....: plot_points=200, thickness=2, label_axes=False) # 3D plot
|
|
833
|
+
sage: graph_S2 = XS.plot(X3, mapping=F, # plot of the sphere # needs sage.plot
|
|
834
|
+
....: number_values=11, color='black')
|
|
835
|
+
sage: show(graph_c + graph_S2) # the loxodrome + the sphere # needs sage.plot
|
|
836
|
+
|
|
837
|
+
.. PLOT::
|
|
838
|
+
|
|
839
|
+
S2 = Manifold(2, 'S^2')
|
|
840
|
+
U = S2.open_subset('U')
|
|
841
|
+
XS = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
|
|
842
|
+
th, ph = XS[:]
|
|
843
|
+
R3 = Manifold(3, 'R^3')
|
|
844
|
+
X3 = R3.chart('x y z')
|
|
845
|
+
F = S2.diff_map(R3, {(XS, X3): [sin(th)*cos(ph), sin(th)*sin(ph),
|
|
846
|
+
cos(th)]}, name='F')
|
|
847
|
+
t = manifolds.RealLine().canonical_coordinate()
|
|
848
|
+
c = S2.curve([2*atan(exp(-t/10)), t], (t, -oo, +oo), name='c')
|
|
849
|
+
graph_c = c.plot(mapping=F, max_range=40, plot_points=200,
|
|
850
|
+
thickness=2, label_axes=False)
|
|
851
|
+
graph_S2 = XS.plot(X3, mapping=F, number_values=11, color='black')
|
|
852
|
+
sphinx_plot(graph_c + graph_S2)
|
|
853
|
+
|
|
854
|
+
Example of use of the argument ``parameters``: we define a curve with
|
|
855
|
+
some symbolic parameters ``a`` and ``b``::
|
|
856
|
+
|
|
857
|
+
sage: a, b = var('a b')
|
|
858
|
+
sage: c = R2.curve([a*cos(t) + b, a*sin(t)], (t, 0, 2*pi), name='c')
|
|
859
|
+
|
|
860
|
+
To make a plot, we set specific values for ``a`` and ``b`` by means
|
|
861
|
+
of the Python dictionary ``parameters``::
|
|
862
|
+
|
|
863
|
+
sage: c.plot(parameters={a: 2, b: -3}, aspect_ratio=1) # needs sage.plot
|
|
864
|
+
Graphics object consisting of 1 graphics primitive
|
|
865
|
+
|
|
866
|
+
.. PLOT::
|
|
867
|
+
|
|
868
|
+
R2 = Manifold(2, 'R^2')
|
|
869
|
+
X = R2.chart('x y')
|
|
870
|
+
t = manifolds.RealLine().canonical_coordinate()
|
|
871
|
+
a, b = var('a b')
|
|
872
|
+
c = R2.curve([a*cos(t) + b, a*sin(t)], (t, 0, 2*pi), name='c')
|
|
873
|
+
g = c.plot(parameters={a: 2, b: -3}, aspect_ratio=1)
|
|
874
|
+
sphinx_plot(g)
|
|
875
|
+
"""
|
|
876
|
+
from sage.manifolds.chart import RealChart
|
|
877
|
+
from sage.misc.functional import numerical_approx
|
|
878
|
+
from sage.rings.infinity import Infinity
|
|
879
|
+
|
|
880
|
+
#
|
|
881
|
+
# Get the @options from kwds
|
|
882
|
+
#
|
|
883
|
+
thickness = kwds.pop('thickness')
|
|
884
|
+
plot_points = kwds.pop('plot_points')
|
|
885
|
+
max_range = kwds.pop('max_range')
|
|
886
|
+
aspect_ratio = kwds.pop('aspect_ratio')
|
|
887
|
+
#
|
|
888
|
+
# The "effective" curve to be plotted
|
|
889
|
+
#
|
|
890
|
+
if mapping is None:
|
|
891
|
+
eff_curve = self
|
|
892
|
+
else:
|
|
893
|
+
eff_curve = mapping.restrict(self.codomain()) * self
|
|
894
|
+
#
|
|
895
|
+
# The chart w.r.t. which the curve is plotted
|
|
896
|
+
#
|
|
897
|
+
if chart is None:
|
|
898
|
+
chart = eff_curve._codomain.default_chart()
|
|
899
|
+
elif not isinstance(chart, RealChart):
|
|
900
|
+
raise TypeError("{} is not a real chart".format(chart))
|
|
901
|
+
#
|
|
902
|
+
# Coordinates of the above chart w.r.t. which the curve is plotted
|
|
903
|
+
#
|
|
904
|
+
if ambient_coords is None:
|
|
905
|
+
ambient_coords = chart[:] # all chart coordinates are used
|
|
906
|
+
n_pc = len(ambient_coords)
|
|
907
|
+
if n_pc != 2 and n_pc != 3:
|
|
908
|
+
raise ValueError("the number of coordinates involved in the " +
|
|
909
|
+
"plot must be either 2 or 3, not {}".format(n_pc))
|
|
910
|
+
# indices of plot coordinates
|
|
911
|
+
ind_pc = [chart[:].index(pc) for pc in ambient_coords]
|
|
912
|
+
#
|
|
913
|
+
# Parameter range for the plot
|
|
914
|
+
#
|
|
915
|
+
if prange is None:
|
|
916
|
+
prange = (self._domain.lower_bound(), self._domain.upper_bound())
|
|
917
|
+
elif not isinstance(prange, (tuple, list)):
|
|
918
|
+
raise TypeError("{} is neither a tuple nor a list".format(prange))
|
|
919
|
+
elif len(prange) != 2:
|
|
920
|
+
raise ValueError("the argument prange must be a tuple/list " +
|
|
921
|
+
"of 2 elements")
|
|
922
|
+
tmin = prange[0]
|
|
923
|
+
tmax = prange[1]
|
|
924
|
+
if tmin == -Infinity:
|
|
925
|
+
tmin = -max_range
|
|
926
|
+
elif not include_end_point[0]:
|
|
927
|
+
tmin = tmin + end_point_offset[0]
|
|
928
|
+
if tmax == Infinity:
|
|
929
|
+
tmax = max_range
|
|
930
|
+
elif not include_end_point[1]:
|
|
931
|
+
tmax = tmax - end_point_offset[1]
|
|
932
|
+
tmin = numerical_approx(tmin)
|
|
933
|
+
tmax = numerical_approx(tmax)
|
|
934
|
+
#
|
|
935
|
+
# The coordinate expression of the effective curve
|
|
936
|
+
#
|
|
937
|
+
transf = eff_curve.coord_functions(chart1=self._domain.canonical_chart(),
|
|
938
|
+
chart2=chart)
|
|
939
|
+
#
|
|
940
|
+
# List of points for the plot curve
|
|
941
|
+
#
|
|
942
|
+
plot_curve = []
|
|
943
|
+
dt = (tmax - tmin) / (plot_points - 1)
|
|
944
|
+
t = tmin
|
|
945
|
+
if parameters is None:
|
|
946
|
+
for i in range(plot_points):
|
|
947
|
+
x = transf(t, simplify=False)
|
|
948
|
+
plot_curve.append( [numerical_approx(x[j]) for j in ind_pc] )
|
|
949
|
+
t += dt
|
|
950
|
+
else:
|
|
951
|
+
for i in range(plot_points):
|
|
952
|
+
x = transf(t, simplify=False)
|
|
953
|
+
plot_curve.append(
|
|
954
|
+
[numerical_approx( x[j].substitute(parameters) )
|
|
955
|
+
for j in ind_pc] )
|
|
956
|
+
t += dt
|
|
957
|
+
|
|
958
|
+
return self._graphics(plot_curve, ambient_coords,
|
|
959
|
+
thickness=thickness,
|
|
960
|
+
aspect_ratio=aspect_ratio, color=color,
|
|
961
|
+
style=style, label_axes=label_axes)
|
|
962
|
+
|
|
963
|
+
def _graphics(self, plot_curve, ambient_coords, thickness=1,
|
|
964
|
+
aspect_ratio='automatic', color='red', style='-',
|
|
965
|
+
label_axes=True):
|
|
966
|
+
r"""
|
|
967
|
+
Plot a 2D or 3D curve in a Cartesian graph with axes labeled by
|
|
968
|
+
the ambient coordinates; it is invoked by the methods
|
|
969
|
+
:meth:`plot` of
|
|
970
|
+
:class:`~sage.manifolds.differentiable.curve.DifferentiableCurve`,
|
|
971
|
+
and its subclasses
|
|
972
|
+
(:class:`~sage.manifolds.differentiable.integrated_curve.IntegratedCurve`,
|
|
973
|
+
:class:`~sage.manifolds.differentiable.integrated_curve.IntegratedAutoparallelCurve`,
|
|
974
|
+
and
|
|
975
|
+
:class:`~sage.manifolds.differentiable.integrated_curve.IntegratedGeodesic`).
|
|
976
|
+
|
|
977
|
+
TESTS::
|
|
978
|
+
|
|
979
|
+
sage: # needs sage.plot
|
|
980
|
+
sage: M = Manifold(2, 'R^2')
|
|
981
|
+
sage: X.<x,y> = M.chart()
|
|
982
|
+
sage: R.<t> = manifolds.RealLine()
|
|
983
|
+
sage: c = M.curve([cos(t), sin(t)], (t, 0, 2*pi), name='c')
|
|
984
|
+
sage: graph = c._graphics([[1,2], [3,4]], [x,y])
|
|
985
|
+
sage: graph._objects[0].xdata == [1,3]
|
|
986
|
+
True
|
|
987
|
+
sage: graph._objects[0].ydata == [2,4]
|
|
988
|
+
True
|
|
989
|
+
sage: graph._objects[0]._options['thickness'] == 1
|
|
990
|
+
True
|
|
991
|
+
sage: graph._extra_kwds['aspect_ratio'] == 'automatic'
|
|
992
|
+
True
|
|
993
|
+
sage: graph._objects[0]._options['rgbcolor'] == 'red'
|
|
994
|
+
True
|
|
995
|
+
sage: graph._objects[0]._options['linestyle'] == '-'
|
|
996
|
+
True
|
|
997
|
+
sage: l = [r'$'+latex(x)+r'$', r'$'+latex(y)+r'$']
|
|
998
|
+
sage: graph._extra_kwds['axes_labels'] == l
|
|
999
|
+
True
|
|
1000
|
+
"""
|
|
1001
|
+
from sage.manifolds.utilities import set_axes_labels
|
|
1002
|
+
from sage.plot.graphics import Graphics
|
|
1003
|
+
from sage.plot.line import line
|
|
1004
|
+
|
|
1005
|
+
#
|
|
1006
|
+
# The plot
|
|
1007
|
+
#
|
|
1008
|
+
n_pc = len(ambient_coords)
|
|
1009
|
+
resu = Graphics()
|
|
1010
|
+
resu += line(plot_curve, color=color, linestyle=style,
|
|
1011
|
+
thickness=thickness)
|
|
1012
|
+
if n_pc == 2: # 2D graphic
|
|
1013
|
+
resu.set_aspect_ratio(aspect_ratio)
|
|
1014
|
+
if label_axes:
|
|
1015
|
+
# We update the dictionary _extra_kwds (options to be passed
|
|
1016
|
+
# to show()), instead of using the method
|
|
1017
|
+
# Graphics.axes_labels() since the latter is not robust w.r.t.
|
|
1018
|
+
# graph addition
|
|
1019
|
+
resu._extra_kwds['axes_labels'] = [r'$'+latex(pc)+r'$'
|
|
1020
|
+
for pc in ambient_coords]
|
|
1021
|
+
else: # 3D graphic
|
|
1022
|
+
if aspect_ratio == 'automatic':
|
|
1023
|
+
aspect_ratio = 1
|
|
1024
|
+
resu.aspect_ratio(aspect_ratio)
|
|
1025
|
+
if label_axes:
|
|
1026
|
+
labels = [str(pc) for pc in ambient_coords]
|
|
1027
|
+
resu = set_axes_labels(resu, *labels)
|
|
1028
|
+
return resu
|