passagemath-plot 10.6.31rc3__cp314-cp314-macosx_13_0_arm64.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-plot might be problematic. Click here for more details.
- passagemath_plot-10.6.31rc3.dist-info/METADATA +172 -0
- passagemath_plot-10.6.31rc3.dist-info/RECORD +82 -0
- passagemath_plot-10.6.31rc3.dist-info/WHEEL +6 -0
- passagemath_plot-10.6.31rc3.dist-info/top_level.txt +2 -0
- passagemath_plot.dylibs/libgfortran.5.dylib +0 -0
- passagemath_plot.dylibs/libgsl.28.dylib +0 -0
- passagemath_plot.dylibs/libopenblasp-r0.3.29.dylib +0 -0
- passagemath_plot.dylibs/libquadmath.0.dylib +0 -0
- sage/all__sagemath_plot.py +15 -0
- sage/ext_data/threejs/animation.css +195 -0
- sage/ext_data/threejs/animation.html +85 -0
- sage/ext_data/threejs/animation.js +273 -0
- sage/ext_data/threejs/fat_lines.js +48 -0
- sage/ext_data/threejs/threejs-version.txt +1 -0
- sage/ext_data/threejs/threejs_template.html +597 -0
- sage/interfaces/all__sagemath_plot.py +1 -0
- sage/interfaces/gnuplot.py +196 -0
- sage/interfaces/jmoldata.py +208 -0
- sage/interfaces/povray.py +56 -0
- sage/plot/all.py +42 -0
- sage/plot/animate.py +1796 -0
- sage/plot/arc.py +504 -0
- sage/plot/arrow.py +671 -0
- sage/plot/bar_chart.py +205 -0
- sage/plot/bezier_path.py +400 -0
- sage/plot/circle.py +435 -0
- sage/plot/colors.py +1606 -0
- sage/plot/complex_plot.cpython-314-darwin.so +0 -0
- sage/plot/complex_plot.pyx +1446 -0
- sage/plot/contour_plot.py +1792 -0
- sage/plot/density_plot.py +318 -0
- sage/plot/disk.py +373 -0
- sage/plot/ellipse.py +375 -0
- sage/plot/graphics.py +3580 -0
- sage/plot/histogram.py +354 -0
- sage/plot/hyperbolic_arc.py +404 -0
- sage/plot/hyperbolic_polygon.py +416 -0
- sage/plot/hyperbolic_regular_polygon.py +296 -0
- sage/plot/line.py +626 -0
- sage/plot/matrix_plot.py +629 -0
- sage/plot/misc.py +509 -0
- sage/plot/multigraphics.py +1294 -0
- sage/plot/plot.py +4183 -0
- sage/plot/plot3d/all.py +23 -0
- sage/plot/plot3d/base.cpython-314-darwin.so +0 -0
- sage/plot/plot3d/base.pxd +12 -0
- sage/plot/plot3d/base.pyx +3378 -0
- sage/plot/plot3d/implicit_plot3d.py +659 -0
- sage/plot/plot3d/implicit_surface.cpython-314-darwin.so +0 -0
- sage/plot/plot3d/implicit_surface.pyx +1453 -0
- sage/plot/plot3d/index_face_set.cpython-314-darwin.so +0 -0
- sage/plot/plot3d/index_face_set.pxd +32 -0
- sage/plot/plot3d/index_face_set.pyx +1873 -0
- sage/plot/plot3d/introduction.py +131 -0
- sage/plot/plot3d/list_plot3d.py +649 -0
- sage/plot/plot3d/parametric_plot3d.py +1130 -0
- sage/plot/plot3d/parametric_surface.cpython-314-darwin.so +0 -0
- sage/plot/plot3d/parametric_surface.pxd +12 -0
- sage/plot/plot3d/parametric_surface.pyx +893 -0
- sage/plot/plot3d/platonic.py +601 -0
- sage/plot/plot3d/plot3d.py +1442 -0
- sage/plot/plot3d/plot_field3d.py +162 -0
- sage/plot/plot3d/point_c.pxi +148 -0
- sage/plot/plot3d/revolution_plot3d.py +309 -0
- sage/plot/plot3d/shapes.cpython-314-darwin.so +0 -0
- sage/plot/plot3d/shapes.pxd +22 -0
- sage/plot/plot3d/shapes.pyx +1382 -0
- sage/plot/plot3d/shapes2.py +1512 -0
- sage/plot/plot3d/tachyon.py +1779 -0
- sage/plot/plot3d/texture.py +453 -0
- sage/plot/plot3d/transform.cpython-314-darwin.so +0 -0
- sage/plot/plot3d/transform.pxd +21 -0
- sage/plot/plot3d/transform.pyx +268 -0
- sage/plot/plot3d/tri_plot.py +589 -0
- sage/plot/plot_field.py +362 -0
- sage/plot/point.py +624 -0
- sage/plot/polygon.py +562 -0
- sage/plot/primitive.py +249 -0
- sage/plot/scatter_plot.py +199 -0
- sage/plot/step.py +85 -0
- sage/plot/streamline_plot.py +328 -0
- sage/plot/text.py +432 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-plot
|
|
2
|
+
# sage.doctest: needs sage.symbolic
|
|
3
|
+
"""
|
|
4
|
+
Plotting 3D fields
|
|
5
|
+
"""
|
|
6
|
+
# ****************************************************************************
|
|
7
|
+
# Copyright (C) 2009 Jason Grout <jason-sage@creativetrax.com>
|
|
8
|
+
#
|
|
9
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
10
|
+
#
|
|
11
|
+
# This code is distributed in the hope that it will be useful,
|
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
14
|
+
# General Public License for more details.
|
|
15
|
+
#
|
|
16
|
+
# The full text of the GPL is available at:
|
|
17
|
+
#
|
|
18
|
+
# https://www.gnu.org/licenses/
|
|
19
|
+
# ****************************************************************************
|
|
20
|
+
|
|
21
|
+
from sage.arith.srange import srange
|
|
22
|
+
from sage.plot.misc import setup_for_eval_on_grid
|
|
23
|
+
from sage.modules.free_module_element import vector
|
|
24
|
+
from sage.plot.plot import plot
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def plot_vector_field3d(functions, xrange, yrange, zrange,
|
|
28
|
+
plot_points=5, colors='jet', center_arrows=False, **kwds):
|
|
29
|
+
r"""
|
|
30
|
+
Plot a 3d vector field.
|
|
31
|
+
|
|
32
|
+
INPUT:
|
|
33
|
+
|
|
34
|
+
- ``functions`` -- list of three functions, representing the x-,
|
|
35
|
+
y-, and z-coordinates of a vector
|
|
36
|
+
|
|
37
|
+
- ``xrange``, ``yrange``, and ``zrange`` -- three tuples of the
|
|
38
|
+
form (var, start, stop), giving the variables and ranges for each axis
|
|
39
|
+
|
|
40
|
+
- ``plot_points`` -- (default: 5) either a number or list of three
|
|
41
|
+
numbers, specifying how many points to plot for each axis
|
|
42
|
+
|
|
43
|
+
- ``colors`` -- (default: ``'jet'``) a color, list of colors (which are
|
|
44
|
+
interpolated between), or matplotlib colormap name, giving the coloring
|
|
45
|
+
of the arrows. If a list of colors or a colormap is given,
|
|
46
|
+
coloring is done as a function of length of the vector
|
|
47
|
+
|
|
48
|
+
- ``center_arrows`` -- (default: ``False``) if ``True``, draw the arrows
|
|
49
|
+
centered on the points; otherwise, draw the arrows with the tail
|
|
50
|
+
at the point
|
|
51
|
+
|
|
52
|
+
- any other keywords are passed on to the :func:`plot` command for each arrow
|
|
53
|
+
|
|
54
|
+
EXAMPLES:
|
|
55
|
+
|
|
56
|
+
A 3d vector field::
|
|
57
|
+
|
|
58
|
+
sage: x,y,z = var('x y z')
|
|
59
|
+
sage: plot_vector_field3d((x*cos(z), -y*cos(z), sin(z)),
|
|
60
|
+
....: (x,0,pi), (y,0,pi), (z,0,pi))
|
|
61
|
+
Graphics3d Object
|
|
62
|
+
|
|
63
|
+
.. PLOT::
|
|
64
|
+
|
|
65
|
+
x,y,z=var('x y z')
|
|
66
|
+
sphinx_plot(plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi)))
|
|
67
|
+
|
|
68
|
+
same example with only a list of colors::
|
|
69
|
+
|
|
70
|
+
sage: plot_vector_field3d((x*cos(z), -y*cos(z), sin(z)),
|
|
71
|
+
....: (x,0,pi), (y,0,pi), (z,0,pi),
|
|
72
|
+
....: colors=['red','green','blue'])
|
|
73
|
+
Graphics3d Object
|
|
74
|
+
|
|
75
|
+
.. PLOT::
|
|
76
|
+
|
|
77
|
+
x,y,z=var('x y z')
|
|
78
|
+
sphinx_plot(plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi),colors=['red','green','blue']))
|
|
79
|
+
|
|
80
|
+
same example with only one color::
|
|
81
|
+
|
|
82
|
+
sage: plot_vector_field3d((x*cos(z), -y*cos(z), sin(z)),
|
|
83
|
+
....: (x,0,pi), (y,0,pi), (z,0,pi), colors='red')
|
|
84
|
+
Graphics3d Object
|
|
85
|
+
|
|
86
|
+
.. PLOT::
|
|
87
|
+
|
|
88
|
+
x,y,z=var('x y z')
|
|
89
|
+
sphinx_plot(plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi),colors='red'))
|
|
90
|
+
|
|
91
|
+
same example with the same plot points for the three axes::
|
|
92
|
+
|
|
93
|
+
sage: plot_vector_field3d((x*cos(z), -y*cos(z), sin(z)),
|
|
94
|
+
....: (x,0,pi), (y,0,pi), (z,0,pi), plot_points=4)
|
|
95
|
+
Graphics3d Object
|
|
96
|
+
|
|
97
|
+
.. PLOT::
|
|
98
|
+
|
|
99
|
+
x,y,z=var('x y z')
|
|
100
|
+
sphinx_plot(plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi),plot_points=4))
|
|
101
|
+
|
|
102
|
+
same example with different number of plot points for each axis::
|
|
103
|
+
|
|
104
|
+
sage: plot_vector_field3d((x*cos(z), -y*cos(z), sin(z)),
|
|
105
|
+
....: (x,0,pi), (y,0,pi), (z,0,pi), plot_points=[3,5,7])
|
|
106
|
+
Graphics3d Object
|
|
107
|
+
|
|
108
|
+
.. PLOT::
|
|
109
|
+
|
|
110
|
+
x,y,z=var('x y z')
|
|
111
|
+
sphinx_plot(plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi),plot_points=[3,5,7]))
|
|
112
|
+
|
|
113
|
+
same example with the arrows centered on the points::
|
|
114
|
+
|
|
115
|
+
sage: plot_vector_field3d((x*cos(z), -y*cos(z), sin(z)),
|
|
116
|
+
....: (x,0,pi), (y,0,pi), (z,0,pi), center_arrows=True)
|
|
117
|
+
Graphics3d Object
|
|
118
|
+
|
|
119
|
+
.. PLOT::
|
|
120
|
+
|
|
121
|
+
x,y,z=var('x y z')
|
|
122
|
+
sphinx_plot(plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi),center_arrows=True))
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
TESTS:
|
|
126
|
+
|
|
127
|
+
This tests that :issue:`2100` is fixed in a way compatible with this command::
|
|
128
|
+
|
|
129
|
+
sage: plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi),center_arrows=True,aspect_ratio=(1,2,1))
|
|
130
|
+
Graphics3d Object
|
|
131
|
+
"""
|
|
132
|
+
(ff, gg, hh), ranges = setup_for_eval_on_grid(functions, [xrange, yrange, zrange], plot_points)
|
|
133
|
+
xpoints, ypoints, zpoints = (srange(*r, include_endpoint=True) for r in ranges)
|
|
134
|
+
points = [vector((i, j, k)) for i in xpoints for j in ypoints for k in zpoints]
|
|
135
|
+
vectors = [vector((ff(*point), gg(*point), hh(*point))) for point in points]
|
|
136
|
+
|
|
137
|
+
try:
|
|
138
|
+
import matplotlib as mpl
|
|
139
|
+
cm = mpl.colormaps[colors]
|
|
140
|
+
except (TypeError, KeyError):
|
|
141
|
+
cm = None
|
|
142
|
+
if cm is None:
|
|
143
|
+
if isinstance(colors, (list, tuple)):
|
|
144
|
+
from matplotlib.colors import LinearSegmentedColormap
|
|
145
|
+
cm = LinearSegmentedColormap.from_list('mymap', colors)
|
|
146
|
+
else:
|
|
147
|
+
def cm(x):
|
|
148
|
+
return colors
|
|
149
|
+
|
|
150
|
+
max_len = max(v.norm() for v in vectors)
|
|
151
|
+
scaled_vectors = [v / max_len for v in vectors]
|
|
152
|
+
|
|
153
|
+
if center_arrows:
|
|
154
|
+
G = sum(plot(v, color=cm(v.norm()), **kwds).translate(p - v / 2)
|
|
155
|
+
for v, p in zip(scaled_vectors, points))
|
|
156
|
+
G._set_extra_kwds(kwds)
|
|
157
|
+
return G
|
|
158
|
+
else:
|
|
159
|
+
G = sum(plot(v, color=cm(v.norm()), **kwds).translate(p)
|
|
160
|
+
for v, p in zip(scaled_vectors, points))
|
|
161
|
+
G._set_extra_kwds(kwds)
|
|
162
|
+
return G
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-plot
|
|
2
|
+
# ****************************************************************************
|
|
3
|
+
# Copyright (C) 2007 Robert Bradshaw <robertwb@math.washington.edu>
|
|
4
|
+
#
|
|
5
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
6
|
+
#
|
|
7
|
+
# This code is distributed in the hope that it will be useful,
|
|
8
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
9
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
10
|
+
# General Public License for more details.
|
|
11
|
+
#
|
|
12
|
+
# The full text of the GPL is available at:
|
|
13
|
+
#
|
|
14
|
+
# https://www.gnu.org/licenses/
|
|
15
|
+
# ****************************************************************************
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# Utility functions for operating on the point_c struct.
|
|
19
|
+
from libc cimport math
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
cdef inline bint point_c_set(point_c* res, P) except -2:
|
|
23
|
+
res.x, res.y, res.z = P[0], P[1], P[2]
|
|
24
|
+
|
|
25
|
+
cdef inline bint point_c_eq(point_c P, point_c Q) noexcept:
|
|
26
|
+
return P.x == Q.x and P.y == Q.y and P.z == Q.z
|
|
27
|
+
|
|
28
|
+
cdef inline bint point_c_isfinite(point_c P) noexcept:
|
|
29
|
+
return math.isfinite(P.x) and math.isfinite(P.y) and math.isfinite(P.z)
|
|
30
|
+
|
|
31
|
+
cdef inline int point_c_cmp(point_c P, point_c Q) noexcept:
|
|
32
|
+
"""
|
|
33
|
+
Lexographic order
|
|
34
|
+
"""
|
|
35
|
+
if P.x == Q.x:
|
|
36
|
+
if P.y == Q.y:
|
|
37
|
+
if P.z == Q.z:
|
|
38
|
+
return 0
|
|
39
|
+
elif P.z < Q.z:
|
|
40
|
+
return -1
|
|
41
|
+
else:
|
|
42
|
+
return 1
|
|
43
|
+
elif P.y < Q.y:
|
|
44
|
+
return -1
|
|
45
|
+
else:
|
|
46
|
+
return 1
|
|
47
|
+
elif P.x < Q.x:
|
|
48
|
+
return -1
|
|
49
|
+
else:
|
|
50
|
+
return 1
|
|
51
|
+
|
|
52
|
+
cdef inline void point_c_update_finite_lower_bound(point_c* res, point_c P) noexcept:
|
|
53
|
+
# We use the condition "not P.x > res.x" so that the condition returns True if res.x is NaN
|
|
54
|
+
if math.isfinite(P.x) and not P.x > res.x:
|
|
55
|
+
res.x = P.x
|
|
56
|
+
if math.isfinite(P.y) and not P.y > res.y:
|
|
57
|
+
res.y = P.y
|
|
58
|
+
if math.isfinite(P.z) and not P.z > res.z:
|
|
59
|
+
res.z = P.z
|
|
60
|
+
|
|
61
|
+
cdef inline void point_c_update_finite_upper_bound(point_c* res, point_c P) noexcept:
|
|
62
|
+
# We use the condition "not P.x < res.x" so that the condition returns True if res.x is NaN
|
|
63
|
+
if math.isfinite(P.x) and not P.x < res.x:
|
|
64
|
+
res.x = P.x
|
|
65
|
+
if math.isfinite(P.y) and not P.y < res.y:
|
|
66
|
+
res.y = P.y
|
|
67
|
+
if math.isfinite(P.z) and not P.z < res.z:
|
|
68
|
+
res.z = P.z
|
|
69
|
+
|
|
70
|
+
cdef inline void point_c_lower_bound(point_c* res, point_c P, point_c Q) noexcept:
|
|
71
|
+
res.x = P.x if P.x < Q.x else Q.x
|
|
72
|
+
res.y = P.y if P.y < Q.y else Q.y
|
|
73
|
+
res.z = P.z if P.z < Q.z else Q.z
|
|
74
|
+
|
|
75
|
+
cdef inline void point_c_upper_bound(point_c* res, point_c P, point_c Q) noexcept:
|
|
76
|
+
res.x = P.x if P.x > Q.x else Q.x
|
|
77
|
+
res.y = P.y if P.y > Q.y else Q.y
|
|
78
|
+
res.z = P.z if P.z > Q.z else Q.z
|
|
79
|
+
|
|
80
|
+
cdef inline void point_c_add(point_c* res, point_c P, point_c Q) noexcept:
|
|
81
|
+
res.x = P.x + Q.x
|
|
82
|
+
res.y = P.y + Q.y
|
|
83
|
+
res.z = P.z + Q.z
|
|
84
|
+
|
|
85
|
+
cdef inline void point_c_sub(point_c* res, point_c P, point_c Q) noexcept:
|
|
86
|
+
res.x = P.x - Q.x
|
|
87
|
+
res.y = P.y - Q.y
|
|
88
|
+
res.z = P.z - Q.z
|
|
89
|
+
|
|
90
|
+
cdef inline void point_c_mul(point_c* res, point_c P, double a) noexcept:
|
|
91
|
+
res.x = a * P.x
|
|
92
|
+
res.y = a * P.y
|
|
93
|
+
res.z = a * P.z
|
|
94
|
+
|
|
95
|
+
cdef inline double point_c_dot(point_c P, point_c Q) noexcept:
|
|
96
|
+
return P.x*Q.x + P.y*Q.y + P.z*Q.z
|
|
97
|
+
|
|
98
|
+
cdef inline void point_c_cross(point_c* res, point_c P, point_c Q) noexcept:
|
|
99
|
+
res.x = P.y * Q.z - P.z * Q.y
|
|
100
|
+
res.y = P.z * Q.x - P.x * Q.z
|
|
101
|
+
res.z = P.x * Q.y - P.y * Q.x
|
|
102
|
+
|
|
103
|
+
cdef inline double point_c_len(point_c P) noexcept:
|
|
104
|
+
return math.sqrt(point_c_dot(P, P))
|
|
105
|
+
|
|
106
|
+
cdef inline void point_c_middle(point_c* res, point_c P, point_c Q, double a) noexcept:
|
|
107
|
+
cdef double b = 1 - a
|
|
108
|
+
res.x = b * P.x + a * Q.x
|
|
109
|
+
res.y = b * P.y + a * Q.y
|
|
110
|
+
res.z = b * P.z + a * Q.z
|
|
111
|
+
|
|
112
|
+
cdef inline void point_c_transform(point_c* res, double* M, point_c P) noexcept:
|
|
113
|
+
"""
|
|
114
|
+
M is a flattened 4x4 matrix, row major, representing a Euclidean Transformation.
|
|
115
|
+
Operate on P as a point.
|
|
116
|
+
"""
|
|
117
|
+
res.x = M[0]*P.x + M[1]*P.y + M[2]*P.z + M[3]
|
|
118
|
+
res.y = M[4]*P.x + M[5]*P.y + M[6]*P.z + M[7]
|
|
119
|
+
res.z = M[8]*P.x + M[9]*P.y + M[10]*P.z + M[11]
|
|
120
|
+
|
|
121
|
+
cdef inline void point_c_stretch(point_c* res, double* M, point_c P) noexcept:
|
|
122
|
+
"""
|
|
123
|
+
M is a flattened 4x4 matrix, row major, representing a Euclidean Transformation.
|
|
124
|
+
Operate on P as a vector (i.e. ignore the translation component)
|
|
125
|
+
"""
|
|
126
|
+
res.x = M[0]*P.x + M[1]*P.y + M[2]*P.z
|
|
127
|
+
res.y = M[4]*P.x + M[5]*P.y + M[6]*P.z
|
|
128
|
+
res.z = M[8]*P.x + M[9]*P.y + M[10]*P.z
|
|
129
|
+
|
|
130
|
+
cdef inline void face_c_normal(point_c* res, face_c face, point_c* vlist) noexcept:
|
|
131
|
+
cdef point_c e1, e2
|
|
132
|
+
point_c_sub(&e1, vlist[face.vertices[0]], vlist[face.vertices[1]])
|
|
133
|
+
point_c_sub(&e2, vlist[face.vertices[2]], vlist[face.vertices[1]])
|
|
134
|
+
point_c_cross(res, e1, e2)
|
|
135
|
+
|
|
136
|
+
cdef inline double cos_face_angle(face_c F, face_c E, point_c* vlist) noexcept:
|
|
137
|
+
cdef point_c nF, nE
|
|
138
|
+
face_c_normal(&nF, F, vlist)
|
|
139
|
+
face_c_normal(&nE, E, vlist)
|
|
140
|
+
cdef double dot = point_c_dot(nF, nE)
|
|
141
|
+
return dot / math.sqrt(point_c_dot(nF, nF)*point_c_dot(nE, nE))
|
|
142
|
+
|
|
143
|
+
cdef inline double sin_face_angle(face_c F, face_c E, point_c* vlist) noexcept:
|
|
144
|
+
cdef point_c nF, nE
|
|
145
|
+
face_c_normal(&nF, F, vlist)
|
|
146
|
+
face_c_normal(&nE, E, vlist)
|
|
147
|
+
cdef double dot = point_c_dot(nF, nE)
|
|
148
|
+
return math.sqrt(1-(dot*dot)/(point_c_dot(nF, nF)*point_c_dot(nE, nE)))
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-plot
|
|
2
|
+
# sage.doctest: needs sage.plot sage.symbolic
|
|
3
|
+
"""
|
|
4
|
+
Surfaces of revolution
|
|
5
|
+
|
|
6
|
+
AUTHORS:
|
|
7
|
+
|
|
8
|
+
- Oscar Gerardo Lazo Arjona (2010): initial version.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
# ****************************************************************************
|
|
12
|
+
# Copyright (C) 2010 Oscar Gerardo Lazo Arjona algebraicamente@gmail.com
|
|
13
|
+
#
|
|
14
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
15
|
+
#
|
|
16
|
+
# This code is distributed in the hope that it will be useful,
|
|
17
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
18
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
19
|
+
# General Public License for more details.
|
|
20
|
+
#
|
|
21
|
+
# The full text of the GPL is available at:
|
|
22
|
+
#
|
|
23
|
+
# https://www.gnu.org/licenses/
|
|
24
|
+
# ****************************************************************************
|
|
25
|
+
from sage.misc.decorators import rename_keyword
|
|
26
|
+
|
|
27
|
+
from sage.plot.plot3d.parametric_plot3d import parametric_plot3d
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@rename_keyword(alpha='opacity')
|
|
31
|
+
def revolution_plot3d(curve, trange, phirange=None, parallel_axis='z', axis=(0, 0), print_vector=False, show_curve=False, **kwds):
|
|
32
|
+
r"""
|
|
33
|
+
Return a plot of a revolved curve.
|
|
34
|
+
|
|
35
|
+
There are three ways to call this function:
|
|
36
|
+
|
|
37
|
+
- ``revolution_plot3d(f,trange)`` where `f` is a function located in the
|
|
38
|
+
`x z` plane.
|
|
39
|
+
|
|
40
|
+
- ``revolution_plot3d((f_x,f_z),trange)`` where `(f_x,f_z)` is a parametric
|
|
41
|
+
curve on the `x z` plane.
|
|
42
|
+
|
|
43
|
+
- ``revolution_plot3d((f_x,f_y,f_z),trange)`` where `(f_x,f_y,f_z)` can be
|
|
44
|
+
any parametric curve.
|
|
45
|
+
|
|
46
|
+
INPUT:
|
|
47
|
+
|
|
48
|
+
- ``curve`` -- a curve to be revolved, specified as a function, a 2-tuple
|
|
49
|
+
or a 3-tuple
|
|
50
|
+
|
|
51
|
+
- ``trange`` -- a 3-tuple `(t,t_{\min},t_{\max})` where t is the
|
|
52
|
+
independent variable of the curve
|
|
53
|
+
|
|
54
|
+
- ``phirange`` -- a 2-tuple of the form `(\phi_{\min},\phi_{\max})`
|
|
55
|
+
(default: `(0,\pi)`) that specifies the angle in which the curve is to be
|
|
56
|
+
revolved
|
|
57
|
+
|
|
58
|
+
- ``parallel_axis`` -- string (one of ``'x'``, ``'y'``, ``'z'``) that
|
|
59
|
+
specifies the coordinate axis parallel to the revolution axis
|
|
60
|
+
|
|
61
|
+
- ``axis`` -- a 2-tuple that specifies the position of the revolution axis.
|
|
62
|
+
If ``parallel_axis`` is:
|
|
63
|
+
|
|
64
|
+
- ``'z'`` -- then ``axis`` is the point in which the revolution axis
|
|
65
|
+
intersects the `x` `y` plane
|
|
66
|
+
|
|
67
|
+
- ``'x'`` -- then ``axis`` is the point in which the revolution axis
|
|
68
|
+
intersects the `y` `z` plane
|
|
69
|
+
|
|
70
|
+
- ``'y'`` -- then ``axis`` is the point in which the revolution axis
|
|
71
|
+
intersects the `x` `z` plane
|
|
72
|
+
|
|
73
|
+
- ``print_vector`` -- if ``True``, the parametrization of the surface of
|
|
74
|
+
revolution will be printed
|
|
75
|
+
|
|
76
|
+
- ``show_curve`` -- if ``True``, the curve will be displayed
|
|
77
|
+
|
|
78
|
+
EXAMPLES:
|
|
79
|
+
|
|
80
|
+
Let's revolve a simple function around different axes::
|
|
81
|
+
|
|
82
|
+
sage: u = var('u')
|
|
83
|
+
sage: f = u^2
|
|
84
|
+
sage: revolution_plot3d(f, (u,0,2),
|
|
85
|
+
....: show_curve=True, opacity=0.7).show(aspect_ratio=(1,1,1))
|
|
86
|
+
|
|
87
|
+
.. PLOT::
|
|
88
|
+
|
|
89
|
+
u = var('u')
|
|
90
|
+
f = u**2
|
|
91
|
+
P = revolution_plot3d(f, (u,0,2), show_curve=True, opacity=0.7).plot()
|
|
92
|
+
sphinx_plot(P)
|
|
93
|
+
|
|
94
|
+
If we move slightly the axis, we get a goblet-like surface::
|
|
95
|
+
|
|
96
|
+
sage: revolution_plot3d(f, (u,0,2), axis=(1,0.2),
|
|
97
|
+
....: show_curve=True, opacity=0.5).show(aspect_ratio=(1,1,1))
|
|
98
|
+
|
|
99
|
+
.. PLOT::
|
|
100
|
+
|
|
101
|
+
u = var('u')
|
|
102
|
+
f = u**2
|
|
103
|
+
P = revolution_plot3d(f, (u,0,2), axis=(1,0.2), show_curve=True, opacity=0.5).plot()
|
|
104
|
+
sphinx_plot(P)
|
|
105
|
+
|
|
106
|
+
A common problem in calculus books, find the volume within the following revolution solid::
|
|
107
|
+
|
|
108
|
+
sage: line = u
|
|
109
|
+
sage: parabola = u^2
|
|
110
|
+
sage: sur1 = revolution_plot3d(line, (u,0,1), opacity=0.5, rgbcolor=(1,0.5,0),
|
|
111
|
+
....: show_curve=True, parallel_axis='x')
|
|
112
|
+
sage: sur2 = revolution_plot3d(parabola, (u,0,1), opacity=0.5, rgbcolor=(0,1,0),
|
|
113
|
+
....: show_curve=True, parallel_axis='x')
|
|
114
|
+
sage: (sur1 + sur2).show()
|
|
115
|
+
|
|
116
|
+
.. PLOT::
|
|
117
|
+
|
|
118
|
+
u = var('u')
|
|
119
|
+
line = u
|
|
120
|
+
parabola = u**2
|
|
121
|
+
sur1 = revolution_plot3d(line, (u,0,1), opacity=0.5, rgbcolor=(1,0.5,0), show_curve=True, parallel_axis='x')
|
|
122
|
+
sur2 = revolution_plot3d(parabola, (u,0,1), opacity=0.5, rgbcolor=(0,1,0), show_curve=True, parallel_axis='x')
|
|
123
|
+
P = sur1 + sur2
|
|
124
|
+
sphinx_plot(P)
|
|
125
|
+
|
|
126
|
+
Now let's revolve a parametrically defined circle. We can play with the topology of the surface by changing the axis,
|
|
127
|
+
an axis in `(0,0)` (as the previous one) will produce a sphere-like surface::
|
|
128
|
+
|
|
129
|
+
sage: u = var('u')
|
|
130
|
+
sage: circle = (cos(u), sin(u))
|
|
131
|
+
sage: revolution_plot3d(circle, (u,0,2*pi), axis=(0,0),
|
|
132
|
+
....: show_curve=True, opacity=0.5).show(aspect_ratio=(1,1,1))
|
|
133
|
+
|
|
134
|
+
.. PLOT::
|
|
135
|
+
|
|
136
|
+
u = var('u')
|
|
137
|
+
circle = (cos(u), sin(u))
|
|
138
|
+
P = revolution_plot3d(circle, (u,0,2*pi), axis=(0,0), show_curve=True, opacity=0.5)
|
|
139
|
+
sphinx_plot(P)
|
|
140
|
+
|
|
141
|
+
An axis on `(0,y)` will produce a cylinder-like surface::
|
|
142
|
+
|
|
143
|
+
sage: revolution_plot3d(circle, (u,0,2*pi), axis=(0,2),
|
|
144
|
+
....: show_curve=True, opacity=0.5).show(aspect_ratio=(1,1,1))
|
|
145
|
+
|
|
146
|
+
.. PLOT::
|
|
147
|
+
|
|
148
|
+
u = var('u')
|
|
149
|
+
circle = (cos(u), sin(u))
|
|
150
|
+
P = revolution_plot3d(circle, (u,0,2*pi), axis=(0,2), show_curve=True, opacity=0.5)
|
|
151
|
+
sphinx_plot(P)
|
|
152
|
+
|
|
153
|
+
And any other axis will produce a torus-like surface::
|
|
154
|
+
|
|
155
|
+
sage: revolution_plot3d(circle, (u,0,2*pi), axis=(2,0),
|
|
156
|
+
....: show_curve=True, opacity=0.5).show(aspect_ratio=(1,1,1))
|
|
157
|
+
|
|
158
|
+
.. PLOT::
|
|
159
|
+
|
|
160
|
+
u = var('u')
|
|
161
|
+
circle = (cos(u), sin(u))
|
|
162
|
+
P = revolution_plot3d(circle, (u,0,2*pi), axis=(2,0), show_curve=True, opacity=0.5)
|
|
163
|
+
sphinx_plot(P)
|
|
164
|
+
|
|
165
|
+
Now, we can get another goblet-like surface by revolving a curve in 3d::
|
|
166
|
+
|
|
167
|
+
sage: u = var('u')
|
|
168
|
+
sage: curve = (u, cos(4*u), u^2)
|
|
169
|
+
sage: P = revolution_plot3d(curve, (u,0,2), parallel_axis='z', axis=(1,.2),
|
|
170
|
+
....: show_curve=True, opacity=0.5)
|
|
171
|
+
sage: P.show(aspect_ratio=(1,1,1))
|
|
172
|
+
|
|
173
|
+
.. PLOT::
|
|
174
|
+
|
|
175
|
+
u = var('u')
|
|
176
|
+
curve = (u, cos(4*u), u**2)
|
|
177
|
+
P = revolution_plot3d(curve, (u,0,2), show_curve=True, parallel_axis='z', axis=(1,.2), opacity=0.5)
|
|
178
|
+
sphinx_plot(P)
|
|
179
|
+
|
|
180
|
+
A curvy curve with only a quarter turn::
|
|
181
|
+
|
|
182
|
+
sage: u = var('u')
|
|
183
|
+
sage: curve = (sin(3*u), .8*cos(4*u), cos(u))
|
|
184
|
+
sage: revolution_plot3d(curve, (u,0,pi), (0,pi/2), parallel_axis='z',
|
|
185
|
+
....: show_curve=True, opacity=0.5).show(aspect_ratio=(1,1,1),
|
|
186
|
+
....: frame=False)
|
|
187
|
+
|
|
188
|
+
.. PLOT::
|
|
189
|
+
|
|
190
|
+
u = var('u')
|
|
191
|
+
curve = (sin(3*u), .8*cos(4*u), cos(u))
|
|
192
|
+
P = revolution_plot3d(curve, (u,0,pi), (0,pi/2), show_curve=True, parallel_axis='z', opacity=0.5)
|
|
193
|
+
sphinx_plot(P)
|
|
194
|
+
|
|
195
|
+
One can also color the surface using a coloring function of two
|
|
196
|
+
parameters and a colormap as follows. Note that the coloring
|
|
197
|
+
function must take values in the interval `[0,1]`. ::
|
|
198
|
+
|
|
199
|
+
sage: u, phi = var('u,phi')
|
|
200
|
+
sage: def cf(u, phi): return sin(phi+u) ^ 2
|
|
201
|
+
sage: curve = (1+u^2/4, 0, u)
|
|
202
|
+
sage: revolution_plot3d(curve, (u,-2,2), (0,2*pi), parallel_axis='z',
|
|
203
|
+
....: color=(cf, colormaps.PiYG)).show(aspect_ratio=(1,1,1))
|
|
204
|
+
|
|
205
|
+
.. PLOT::
|
|
206
|
+
|
|
207
|
+
u, phi = var('u,phi')
|
|
208
|
+
def cf(u, phi): return sin(phi+u) ** 2
|
|
209
|
+
curve = (1+u**2/4, 0, u)
|
|
210
|
+
P = revolution_plot3d(curve, (u,-2,2), (0,2*pi), parallel_axis='z', color=(cf, colormaps.PiYG))
|
|
211
|
+
sphinx_plot(P)
|
|
212
|
+
|
|
213
|
+
The first parameter of the coloring function will be identified with the
|
|
214
|
+
parameter of the curve, and the second with the angle parameter.
|
|
215
|
+
|
|
216
|
+
Another colored example, illustrating that one can use (colormap, color function) instead of (color function, colormap)::
|
|
217
|
+
|
|
218
|
+
sage: u, phi = var('u,phi')
|
|
219
|
+
sage: def cf(u, phi): return float(2 * u / pi) % 1
|
|
220
|
+
sage: curve = (sin(u), 0, u)
|
|
221
|
+
sage: revolution_plot3d(curve, (u,0,pi), (0,2*pi), parallel_axis='z',
|
|
222
|
+
....: color=(colormaps.brg, cf)).show(aspect_ratio=1)
|
|
223
|
+
|
|
224
|
+
.. PLOT::
|
|
225
|
+
|
|
226
|
+
u, phi = var('u,phi')
|
|
227
|
+
def cf(u, phi): return float(2 * u / pi) % 1
|
|
228
|
+
curve = (sin(u), 0, u)
|
|
229
|
+
P = revolution_plot3d(curve, (u,0,pi), (0,2*pi), parallel_axis='z', color=(colormaps.brg, cf))
|
|
230
|
+
sphinx_plot(P)
|
|
231
|
+
"""
|
|
232
|
+
from sage.symbolic.ring import SR
|
|
233
|
+
from sage.symbolic.constants import pi
|
|
234
|
+
from sage.misc.functional import sqrt
|
|
235
|
+
from sage.functions.trig import sin
|
|
236
|
+
from sage.functions.trig import cos
|
|
237
|
+
from sage.functions.trig import atan2
|
|
238
|
+
|
|
239
|
+
if parallel_axis not in ['x', 'y', 'z']:
|
|
240
|
+
raise ValueError("parallel_axis must be either 'x', 'y', or 'z'")
|
|
241
|
+
|
|
242
|
+
vart = trange[0]
|
|
243
|
+
|
|
244
|
+
if str(vart) == 'phi':
|
|
245
|
+
phi = SR.var('fi')
|
|
246
|
+
else:
|
|
247
|
+
phi = SR.var('phi')
|
|
248
|
+
|
|
249
|
+
if phirange is None: # this if-else provides a phirange
|
|
250
|
+
phirange = (phi, 0, 2 * pi)
|
|
251
|
+
elif len(phirange) == 3:
|
|
252
|
+
phi = phirange[0]
|
|
253
|
+
else:
|
|
254
|
+
phirange = (phi, phirange[0], phirange[1])
|
|
255
|
+
|
|
256
|
+
if isinstance(curve, (tuple, list)):
|
|
257
|
+
# this if-else provides a vector v to be plotted
|
|
258
|
+
# if curve is a tuple or a list of length 2, it is interpreted as a parametric curve
|
|
259
|
+
# in the x-z plane.
|
|
260
|
+
# if it is of length 3 it is interpreted as a parametric curve in 3d space
|
|
261
|
+
|
|
262
|
+
if len(curve) == 2:
|
|
263
|
+
x = curve[0]
|
|
264
|
+
y = 0
|
|
265
|
+
z = curve[1]
|
|
266
|
+
elif len(curve) == 3:
|
|
267
|
+
x = curve[0]
|
|
268
|
+
y = curve[1]
|
|
269
|
+
z = curve[2]
|
|
270
|
+
else:
|
|
271
|
+
x = vart
|
|
272
|
+
y = 0
|
|
273
|
+
z = curve
|
|
274
|
+
|
|
275
|
+
phase = 0
|
|
276
|
+
if parallel_axis == 'z':
|
|
277
|
+
x0 = axis[0]
|
|
278
|
+
y0 = axis[1]
|
|
279
|
+
# (0,0) must be handled separately for the phase value
|
|
280
|
+
if x0 != 0 or y0 != 0:
|
|
281
|
+
phase = atan2(y - y0, x - x0)
|
|
282
|
+
R = sqrt((x-x0)**2 + (y-y0)**2)
|
|
283
|
+
v = (R*cos(phi+phase)+x0, R*sin(phi+phase)+y0, z)
|
|
284
|
+
elif parallel_axis == 'x':
|
|
285
|
+
y0 = axis[0]
|
|
286
|
+
z0 = axis[1]
|
|
287
|
+
# (0,0) must be handled separately for the phase value
|
|
288
|
+
if z0 != 0 or y0 != 0:
|
|
289
|
+
phase = atan2(z - z0, y - y0)
|
|
290
|
+
R = sqrt((y-y0)**2 + (z-z0)**2)
|
|
291
|
+
v = (x, R*cos(phi+phase)+y0, R*sin(phi+phase)+z0)
|
|
292
|
+
elif parallel_axis == 'y':
|
|
293
|
+
x0 = axis[0]
|
|
294
|
+
z0 = axis[1]
|
|
295
|
+
# (0,0) must be handled separately for the phase value
|
|
296
|
+
if z0 != 0 or x0 != 0:
|
|
297
|
+
phase = atan2(z - z0, x - x0)
|
|
298
|
+
R = sqrt((x-x0)**2 + (z-z0)**2)
|
|
299
|
+
v = (R*cos(phi+phase)+x0, y, R*sin(phi+phase)+z0)
|
|
300
|
+
|
|
301
|
+
if print_vector:
|
|
302
|
+
print(v)
|
|
303
|
+
|
|
304
|
+
if show_curve:
|
|
305
|
+
curveplot = parametric_plot3d((x, y, z), trange, thickness=2,
|
|
306
|
+
rgbcolor=(1, 0, 0))
|
|
307
|
+
return parametric_plot3d(v, trange, phirange, **kwds) + curveplot
|
|
308
|
+
|
|
309
|
+
return parametric_plot3d(v, trange, phirange, **kwds)
|
|
Binary file
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-plot
|
|
2
|
+
from sage.plot.plot3d.parametric_surface cimport ParametricSurface
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
cdef class Cone(ParametricSurface):
|
|
6
|
+
cdef double radius
|
|
7
|
+
cdef double height
|
|
8
|
+
cdef bint closed
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
cdef class Cylinder(ParametricSurface):
|
|
12
|
+
cdef double radius
|
|
13
|
+
cdef double height
|
|
14
|
+
cdef bint closed
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
cdef class Sphere(ParametricSurface):
|
|
18
|
+
cdef double radius
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
cdef class Torus(ParametricSurface):
|
|
22
|
+
cdef double R, r
|