passagemath-plot 10.6.31rc3__cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.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 +81 -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.libs/libgfortran-e1b7dfc8.so.5.0.0 +0 -0
- passagemath_plot.libs/libgsl-e3525837.so.28.0.0 +0 -0
- passagemath_plot.libs/libopenblasp-r0-4c5b64b1.3.29.so +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-aarch64-linux-gnu.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-aarch64-linux-gnu.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-aarch64-linux-gnu.so +0 -0
- sage/plot/plot3d/implicit_surface.pyx +1453 -0
- sage/plot/plot3d/index_face_set.cpython-314-aarch64-linux-gnu.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-aarch64-linux-gnu.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-aarch64-linux-gnu.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-aarch64-linux-gnu.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,1442 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-plot
|
|
2
|
+
# sage.doctest: needs sage.symbolic
|
|
3
|
+
r"""
|
|
4
|
+
Plotting functions
|
|
5
|
+
|
|
6
|
+
EXAMPLES::
|
|
7
|
+
|
|
8
|
+
sage: x, y = var('x y')
|
|
9
|
+
sage: W = plot3d(sin(pi*((x)^2 + (y)^2))/2, (x, -1, 1), (y, -1, 1),
|
|
10
|
+
....: frame=False, color='purple', opacity=0.8)
|
|
11
|
+
sage: S = sphere((0, 0, 0), size=0.3, color='red', aspect_ratio=[1,1,1])
|
|
12
|
+
sage: show(W + S, figsize=8)
|
|
13
|
+
|
|
14
|
+
.. PLOT::
|
|
15
|
+
|
|
16
|
+
x, y = var('x y')
|
|
17
|
+
W = plot3d(sin(pi*((x)**2 + (y)**2))/2, (x, -1, 1), (y, -1, 1), frame=False, color='purple', opacity=0.8)
|
|
18
|
+
S = sphere((0, 0, 0), size=0.3, color='red', aspect_ratio=[1, 1, 1])
|
|
19
|
+
sphinx_plot(W + S)
|
|
20
|
+
|
|
21
|
+
::
|
|
22
|
+
|
|
23
|
+
sage: def f(x, y):
|
|
24
|
+
....: return math.sin(y^2 + x^2)/math.sqrt(x^2 + y^2 + 0.0001)
|
|
25
|
+
sage: P = plot3d(f, (-3, 3),(-3, 3), adaptive=True,
|
|
26
|
+
....: color=rainbow(60, 'rgbtuple'), max_bend=.1, max_depth=15)
|
|
27
|
+
sage: P.show()
|
|
28
|
+
|
|
29
|
+
.. PLOT::
|
|
30
|
+
|
|
31
|
+
def f(x, y): return math.sin(y**2 + x**2)/math.sqrt(x**2 + y**2 + 0.0001)
|
|
32
|
+
P = plot3d(f, (-3, 3), (-3, 3), adaptive=True, color=rainbow(60, 'rgbtuple'), max_bend=.1, max_depth=15)
|
|
33
|
+
sphinx_plot(P)
|
|
34
|
+
|
|
35
|
+
::
|
|
36
|
+
|
|
37
|
+
sage: def f(x, y):
|
|
38
|
+
....: return math.exp(x/5)*math.sin(y)
|
|
39
|
+
....:
|
|
40
|
+
sage: P = plot3d(f, (-5, 5), (-5, 5), adaptive=True, color=['red', 'yellow'])
|
|
41
|
+
sage: from sage.plot.plot3d.plot3d import axes
|
|
42
|
+
sage: S = P + axes(6, color='black')
|
|
43
|
+
sage: S.show()
|
|
44
|
+
|
|
45
|
+
.. PLOT::
|
|
46
|
+
|
|
47
|
+
def f(x, y): return math.exp(x/5)*math.sin(y)
|
|
48
|
+
P = plot3d(f, (-5, 5), (-5, 5), adaptive=True, color=['red', 'yellow'])
|
|
49
|
+
from sage.plot.plot3d.plot3d import axes
|
|
50
|
+
S = P + axes(6, color='black')
|
|
51
|
+
sphinx_plot(S)
|
|
52
|
+
|
|
53
|
+
Here is an example using a colormap and a color function ``c``::
|
|
54
|
+
|
|
55
|
+
sage: x, y = var('x y')
|
|
56
|
+
sage: cm = colormaps.hsv
|
|
57
|
+
sage: def c(x, y): return float((x + y + x*y)/15) % 1
|
|
58
|
+
sage: plot3d(x*x + y*y, (x, -4, 4), (y, -4, 4), color=(c, cm))
|
|
59
|
+
Graphics3d Object
|
|
60
|
+
|
|
61
|
+
.. PLOT::
|
|
62
|
+
|
|
63
|
+
x, y = var('x y')
|
|
64
|
+
cm = colormaps.hsv
|
|
65
|
+
def c(x, y): return float((x + y + x*y)/15) % 1
|
|
66
|
+
sphinx_plot(plot3d(x*x + y*y,(x, -4, 4), (y, -4, 4), color=(c, cm)))
|
|
67
|
+
|
|
68
|
+
Beware that the color function must take values between 0 and 1.
|
|
69
|
+
|
|
70
|
+
We plot "cape man"::
|
|
71
|
+
|
|
72
|
+
sage: S = sphere(size=.5, color='yellow')
|
|
73
|
+
|
|
74
|
+
::
|
|
75
|
+
|
|
76
|
+
sage: from sage.plot.plot3d.shapes import Cone
|
|
77
|
+
sage: S += Cone(.5, .5, color='red').translate(0,0,.3)
|
|
78
|
+
|
|
79
|
+
::
|
|
80
|
+
|
|
81
|
+
sage: S += sphere((.45, -.1, .15), size=.1, color='white')
|
|
82
|
+
sage: S += sphere((.51,-.1,.17), size=.05, color='black')
|
|
83
|
+
sage: S += sphere((.45, .1, .15), size=.1, color='white')
|
|
84
|
+
sage: S += sphere((.51, .1,.17), size=.05, color='black')
|
|
85
|
+
sage: S += sphere((.5, 0, -.2), size=.1, color='yellow')
|
|
86
|
+
sage: def f(x, y): return math.exp(x/5)*math.cos(y)
|
|
87
|
+
sage: P = plot3d(f, (-5, 5), (-5, 5), adaptive=True,
|
|
88
|
+
....: color=['red','yellow'], max_depth=10)
|
|
89
|
+
sage: cape_man = P.scale(.2) + S.translate(1, 0, 0)
|
|
90
|
+
sage: cape_man.show(aspect_ratio=[1, 1, 1])
|
|
91
|
+
|
|
92
|
+
.. PLOT::
|
|
93
|
+
|
|
94
|
+
S = sphere(size=.5, color='yellow')
|
|
95
|
+
from sage.plot.plot3d.shapes import Cone
|
|
96
|
+
S += Cone(.5, .5, color='red').translate(0,0,.3)
|
|
97
|
+
S += sphere((.45, -.1, .15), size=.1, color='white') + sphere((.51,-.1,.17), size=.05, color='black')
|
|
98
|
+
S += sphere((.45, .1, .15), size=.1, color='white') + sphere((.51, .1,.17), size=.05, color='black')
|
|
99
|
+
S += sphere((.5, 0, -.2), size=.1, color='yellow')
|
|
100
|
+
def f(x, y): return math.exp(x/5)*math.cos(y)
|
|
101
|
+
P = plot3d(f, (-5, 5), (-5, 5), adaptive=True, color=['red','yellow'], max_depth=10)
|
|
102
|
+
cape_man = P.scale(.2) + S.translate(1, 0, 0)
|
|
103
|
+
cape_man.aspect_ratio([1, 1, 1])
|
|
104
|
+
sphinx_plot(cape_man)
|
|
105
|
+
|
|
106
|
+
Or, we plot a very simple function indeed::
|
|
107
|
+
|
|
108
|
+
sage: plot3d(pi, (-1,1), (-1,1))
|
|
109
|
+
Graphics3d Object
|
|
110
|
+
|
|
111
|
+
.. PLOT::
|
|
112
|
+
|
|
113
|
+
sphinx_plot(plot3d(pi, (-1,1), (-1,1)))
|
|
114
|
+
|
|
115
|
+
Transparent with fractional opacity value::
|
|
116
|
+
|
|
117
|
+
sage: plot3d(lambda x, y: x^2 + y^2, (-2,2), (-2,2), opacity=8/10)
|
|
118
|
+
Graphics3d Object
|
|
119
|
+
|
|
120
|
+
.. TODO::
|
|
121
|
+
|
|
122
|
+
Add support for smooth triangles.
|
|
123
|
+
|
|
124
|
+
AUTHORS:
|
|
125
|
+
|
|
126
|
+
- Tom Boothby: adaptive refinement triangles
|
|
127
|
+
|
|
128
|
+
- Josh Kantor: adaptive refinement triangles
|
|
129
|
+
|
|
130
|
+
- Robert Bradshaw (2007-08): initial version of this file
|
|
131
|
+
|
|
132
|
+
- William Stein (2007-12, 2008-01): improving 3d plotting
|
|
133
|
+
|
|
134
|
+
- Oscar Lazo, William Cauchois, Jason Grout (2009-2010): Adding coordinate transformations
|
|
135
|
+
"""
|
|
136
|
+
# ****************************************************************************
|
|
137
|
+
# Copyright (C) 2007 Robert Bradshaw <robertwb@math.washington.edu>
|
|
138
|
+
#
|
|
139
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
140
|
+
#
|
|
141
|
+
# This code is distributed in the hope that it will be useful,
|
|
142
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
143
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
144
|
+
# General Public License for more details.
|
|
145
|
+
#
|
|
146
|
+
# The full text of the GPL is available at:
|
|
147
|
+
#
|
|
148
|
+
# https://www.gnu.org/licenses/
|
|
149
|
+
# ****************************************************************************
|
|
150
|
+
|
|
151
|
+
from sage.misc.lazy_import import lazy_import
|
|
152
|
+
from sage.misc.sageinspect import sage_getargspec, is_function_or_cython_function
|
|
153
|
+
from sage.plot.colors import rainbow
|
|
154
|
+
from sage.plot.plot3d.base import Graphics3dGroup
|
|
155
|
+
from sage.plot.plot3d.index_face_set import IndexFaceSet
|
|
156
|
+
from sage.plot.plot3d.shapes import arrow3d
|
|
157
|
+
from sage.plot.plot3d.texture import Texture
|
|
158
|
+
from sage.plot.plot3d.tri_plot import TrianglePlot
|
|
159
|
+
from . import parametric_plot3d
|
|
160
|
+
lazy_import("sage.functions.trig", ["cos", "sin"])
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
class _Coordinates:
|
|
164
|
+
"""
|
|
165
|
+
This abstract class encapsulates a new coordinate system for plotting.
|
|
166
|
+
Sub-classes must implement the :meth:`transform` method which, given
|
|
167
|
+
symbolic variables to use, generates a 3-tuple of functions in terms of
|
|
168
|
+
those variables that can be used to find the Cartesian (X, Y, and Z)
|
|
169
|
+
coordinates for any point in this space.
|
|
170
|
+
|
|
171
|
+
INPUT:
|
|
172
|
+
|
|
173
|
+
- ``dep_var`` -- the dependent variable (the function value will be
|
|
174
|
+
|
|
175
|
+
- ``indep_vars`` -- list of independent variables (the parameters will be
|
|
176
|
+
substituted for these)
|
|
177
|
+
"""
|
|
178
|
+
def __init__(self, dep_var, indep_vars):
|
|
179
|
+
"""
|
|
180
|
+
Initialize.
|
|
181
|
+
|
|
182
|
+
TESTS:
|
|
183
|
+
|
|
184
|
+
Because the base :class:`_Coordinates` class automatically checks the
|
|
185
|
+
initializing variables with the transform method, :class:`_Coordinates`
|
|
186
|
+
cannot be instantiated by itself. We test a subclass::
|
|
187
|
+
|
|
188
|
+
sage: from sage.plot.plot3d.plot3d import _ArbitraryCoordinates as arb
|
|
189
|
+
sage: x,y,z=var('x,y,z')
|
|
190
|
+
sage: arb((x+z,y*z,z), z, (x,y))
|
|
191
|
+
Arbitrary Coordinates coordinate transform (z in terms of x, y)
|
|
192
|
+
"""
|
|
193
|
+
all_vars = sage_getargspec(self.transform).args[1:]
|
|
194
|
+
A = set(all_vars)
|
|
195
|
+
B = set(indep_vars + [dep_var])
|
|
196
|
+
if A != B:
|
|
197
|
+
raise ValueError('variables were specified incorrectly for this '
|
|
198
|
+
'coordinate system; incorrect variables '
|
|
199
|
+
'were %s' % list(A.symmetric_difference(B)))
|
|
200
|
+
self.dep_var = dep_var
|
|
201
|
+
self.indep_vars = indep_vars
|
|
202
|
+
|
|
203
|
+
@property
|
|
204
|
+
def _name(self):
|
|
205
|
+
"""
|
|
206
|
+
A default name for a coordinate system. Override this in a
|
|
207
|
+
subclass to set a different name.
|
|
208
|
+
|
|
209
|
+
TESTS::
|
|
210
|
+
|
|
211
|
+
sage: from sage.plot.plot3d.plot3d import _ArbitraryCoordinates as arb
|
|
212
|
+
sage: x,y,z=var('x,y,z')
|
|
213
|
+
sage: c=arb((x+z,y*z,z), z, (x,y))
|
|
214
|
+
sage: c._name
|
|
215
|
+
'Arbitrary Coordinates'
|
|
216
|
+
"""
|
|
217
|
+
return self.__class__.__name__
|
|
218
|
+
|
|
219
|
+
def transform(self, **kwds):
|
|
220
|
+
"""
|
|
221
|
+
Return the transformation for this coordinate system in terms of the
|
|
222
|
+
specified variables (which should be keywords).
|
|
223
|
+
|
|
224
|
+
TESTS::
|
|
225
|
+
|
|
226
|
+
sage: from sage.plot.plot3d.plot3d import _ArbitraryCoordinates as arb
|
|
227
|
+
sage: x,y,z=var('x,y,z')
|
|
228
|
+
sage: c=arb((x+z,y*z,z), z, (x,y))
|
|
229
|
+
sage: c.transform(x=1,y=2,z=3)
|
|
230
|
+
(4, 6, 3)
|
|
231
|
+
"""
|
|
232
|
+
raise NotImplementedError
|
|
233
|
+
|
|
234
|
+
def to_cartesian(self, func, params=None):
|
|
235
|
+
"""
|
|
236
|
+
Return a 3-tuple of functions, parameterized over ``params``, that
|
|
237
|
+
represents the Cartesian coordinates of the value of ``func``.
|
|
238
|
+
|
|
239
|
+
INPUT:
|
|
240
|
+
|
|
241
|
+
- ``func`` -- function in this coordinate space; corresponds
|
|
242
|
+
to the independent variable
|
|
243
|
+
|
|
244
|
+
- ``params`` -- the parameters of ``func``; corresponds to
|
|
245
|
+
the dependent variables
|
|
246
|
+
|
|
247
|
+
EXAMPLES::
|
|
248
|
+
|
|
249
|
+
sage: from sage.plot.plot3d.plot3d import _ArbitraryCoordinates
|
|
250
|
+
sage: x, y, z = var('x y z')
|
|
251
|
+
sage: T = _ArbitraryCoordinates((x + y, x - y, z), z,[x,y])
|
|
252
|
+
sage: f(x, y) = 2*x+y
|
|
253
|
+
sage: T.to_cartesian(f, [x, y])
|
|
254
|
+
(x + y, x - y, 2*x + y)
|
|
255
|
+
sage: [h(1,2) for h in T.to_cartesian(lambda x,y: 2*x+y)]
|
|
256
|
+
[3.0, -1.0, 4.0]
|
|
257
|
+
|
|
258
|
+
We try to return a function having the same variable names as
|
|
259
|
+
the function passed in::
|
|
260
|
+
|
|
261
|
+
sage: from sage.plot.plot3d.plot3d import _ArbitraryCoordinates
|
|
262
|
+
sage: x, y, z = var('x y z')
|
|
263
|
+
sage: T = _ArbitraryCoordinates((x + y, x - y, z), z,[x,y])
|
|
264
|
+
sage: f(a, b) = 2*a+b
|
|
265
|
+
sage: T.to_cartesian(f, [a, b])
|
|
266
|
+
(a + b, a - b, 2*a + b)
|
|
267
|
+
|
|
268
|
+
sage: t1,t2,t3=T.to_cartesian(lambda a,b: 2*a+b)
|
|
269
|
+
sage: from sage.misc.sageinspect import sage_getargspec
|
|
270
|
+
sage: sage_getargspec(t1)
|
|
271
|
+
FullArgSpec(args=['a', 'b'], varargs=None, varkw=None, defaults=None,
|
|
272
|
+
kwonlyargs=[], kwonlydefaults=None, annotations={})
|
|
273
|
+
sage: sage_getargspec(t2)
|
|
274
|
+
FullArgSpec(args=['a', 'b'], varargs=None, varkw=None, defaults=None,
|
|
275
|
+
kwonlyargs=[], kwonlydefaults=None, annotations={})
|
|
276
|
+
sage: sage_getargspec(t3)
|
|
277
|
+
FullArgSpec(args=['a', 'b'], varargs=None, varkw=None, defaults=None,
|
|
278
|
+
kwonlyargs=[], kwonlydefaults=None, annotations={})
|
|
279
|
+
|
|
280
|
+
sage: def g(a, b): return 2*a+b
|
|
281
|
+
sage: t1,t2,t3=T.to_cartesian(g)
|
|
282
|
+
sage: sage_getargspec(t1)
|
|
283
|
+
FullArgSpec(args=['a', 'b'], varargs=None, varkw=None, defaults=None,
|
|
284
|
+
kwonlyargs=[], kwonlydefaults=None, annotations={})
|
|
285
|
+
sage: t1,t2,t3=T.to_cartesian(2*a+b)
|
|
286
|
+
sage: sage_getargspec(t1)
|
|
287
|
+
FullArgSpec(args=['a', 'b'], varargs=None, varkw=None, defaults=None,
|
|
288
|
+
kwonlyargs=[], kwonlydefaults=None, annotations={})
|
|
289
|
+
|
|
290
|
+
If we cannot guess the right parameter names, then the
|
|
291
|
+
parameters are named `u` and `v`::
|
|
292
|
+
|
|
293
|
+
sage: from sage.plot.plot3d.plot3d import _ArbitraryCoordinates
|
|
294
|
+
sage: from sage.misc.sageinspect import sage_getargspec
|
|
295
|
+
sage: x, y, z = var('x y z')
|
|
296
|
+
sage: T = _ArbitraryCoordinates((x + y, x - y, z), z,[x,y])
|
|
297
|
+
sage: t1,t2,t3=T.to_cartesian(operator.add)
|
|
298
|
+
sage: sage_getargspec(t1)
|
|
299
|
+
FullArgSpec(args=['u', 'v'], varargs=None, varkw=None, defaults=None,
|
|
300
|
+
kwonlyargs=[], kwonlydefaults=None, annotations={})
|
|
301
|
+
sage: [h(1,2) for h in T.to_cartesian(operator.mul)]
|
|
302
|
+
[3.0, -1.0, 2.0]
|
|
303
|
+
sage: [h(u=1,v=2) for h in T.to_cartesian(operator.mul)]
|
|
304
|
+
[3.0, -1.0, 2.0]
|
|
305
|
+
|
|
306
|
+
The output of the function ``func`` is coerced to a float when
|
|
307
|
+
it is evaluated if the function is something like a lambda or
|
|
308
|
+
python callable. This takes care of situations like f returning a
|
|
309
|
+
singleton numpy array, for example.
|
|
310
|
+
|
|
311
|
+
sage: from numpy import array
|
|
312
|
+
sage: v_phi=array([ 0., 1.57079637, 3.14159274, 4.71238911, 6.28318548])
|
|
313
|
+
sage: v_theta=array([ 0., 0.78539819, 1.57079637, 2.35619456, 3.14159274])
|
|
314
|
+
sage: m_r=array([[ 0.16763356, 0.25683223, 0.16649297, 0.10594339, 0.55282422],
|
|
315
|
+
....: [ 0.16763356, 0.19993708, 0.31403568, 0.47359696, 0.55282422],
|
|
316
|
+
....: [ 0.16763356, 0.25683223, 0.16649297, 0.10594339, 0.55282422],
|
|
317
|
+
....: [ 0.16763356, 0.19993708, 0.31403568, 0.47359696, 0.55282422],
|
|
318
|
+
....: [ 0.16763356, 0.25683223, 0.16649297, 0.10594339, 0.55282422]])
|
|
319
|
+
sage: import scipy.interpolate
|
|
320
|
+
sage: f=scipy.interpolate.RectBivariateSpline(v_phi,v_theta,m_r).ev
|
|
321
|
+
sage: spherical_plot3d(f,(0,2*pi),(0,pi))
|
|
322
|
+
Graphics3d Object
|
|
323
|
+
"""
|
|
324
|
+
from sage.structure.element import Expression
|
|
325
|
+
from sage.rings.real_mpfr import RealNumber
|
|
326
|
+
from sage.rings.integer import Integer
|
|
327
|
+
if params is not None and isinstance(func, (Expression,
|
|
328
|
+
RealNumber,
|
|
329
|
+
Integer)):
|
|
330
|
+
return self.transform(**{
|
|
331
|
+
self.dep_var: func,
|
|
332
|
+
self.indep_vars[0]: params[0],
|
|
333
|
+
self.indep_vars[1]: params[1]
|
|
334
|
+
})
|
|
335
|
+
else:
|
|
336
|
+
# func might be a lambda or a Python callable; this makes it slightly
|
|
337
|
+
# more complex.
|
|
338
|
+
import sage.symbolic.ring
|
|
339
|
+
dep_var_dummy = sage.symbolic.ring.var(self.dep_var)
|
|
340
|
+
indep_var_dummies = sage.symbolic.ring.var(','.join(self.indep_vars))
|
|
341
|
+
transformation = self.transform(**{
|
|
342
|
+
self.dep_var: dep_var_dummy,
|
|
343
|
+
self.indep_vars[0]: indep_var_dummies[0],
|
|
344
|
+
self.indep_vars[1]: indep_var_dummies[1]
|
|
345
|
+
})
|
|
346
|
+
if params is None:
|
|
347
|
+
if callable(func):
|
|
348
|
+
params = _find_arguments_for_callable(func)
|
|
349
|
+
if not params:
|
|
350
|
+
params = ['u', 'v']
|
|
351
|
+
else:
|
|
352
|
+
raise ValueError("function is not callable")
|
|
353
|
+
|
|
354
|
+
def subs_func(t):
|
|
355
|
+
# We use eval so that the lambda function has the same
|
|
356
|
+
# variable names as the original function
|
|
357
|
+
ll = f"""lambda {params[0]},{params[1]}: t.subs({{
|
|
358
|
+
dep_var_dummy: float(func({params[0]}, {params[1]})),
|
|
359
|
+
indep_var_dummies[0]: float({params[0]}),
|
|
360
|
+
indep_var_dummies[1]: float({params[1]})
|
|
361
|
+
}})"""
|
|
362
|
+
return eval(ll, {'t': t, 'func': func,
|
|
363
|
+
'dep_var_dummy': dep_var_dummy,
|
|
364
|
+
'indep_var_dummies': indep_var_dummies})
|
|
365
|
+
return [subs_func(m) for m in transformation]
|
|
366
|
+
|
|
367
|
+
def __repr__(self):
|
|
368
|
+
"""
|
|
369
|
+
Print out a coordinate system.
|
|
370
|
+
|
|
371
|
+
::
|
|
372
|
+
|
|
373
|
+
sage: from sage.plot.plot3d.plot3d import _ArbitraryCoordinates as arb
|
|
374
|
+
sage: x,y,z=var('x,y,z')
|
|
375
|
+
sage: c=arb((x+z,y*z,z), z, (x,y))
|
|
376
|
+
sage: c
|
|
377
|
+
Arbitrary Coordinates coordinate transform (z in terms of x, y)
|
|
378
|
+
sage: c.__dict__['_name'] = 'My Special Coordinates'
|
|
379
|
+
sage: c
|
|
380
|
+
My Special Coordinates coordinate transform (z in terms of x, y)
|
|
381
|
+
"""
|
|
382
|
+
return '{} coordinate transform ({} in terms of {})'.format(self._name, self.dep_var, ', '.join(self.indep_vars))
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
def _find_arguments_for_callable(func):
|
|
386
|
+
"""
|
|
387
|
+
Find the names of arguments (that do not have default values) for
|
|
388
|
+
a callable function, taking care of several special cases in Sage.
|
|
389
|
+
|
|
390
|
+
If the parameters cannot be found, then return ``[]``.
|
|
391
|
+
|
|
392
|
+
EXAMPLES::
|
|
393
|
+
|
|
394
|
+
sage: from sage.plot.plot3d.plot3d import _find_arguments_for_callable
|
|
395
|
+
sage: _find_arguments_for_callable(lambda x,y: x+y)
|
|
396
|
+
['x', 'y']
|
|
397
|
+
sage: def f(a, b, c): return a+b+c
|
|
398
|
+
sage: _find_arguments_for_callable(f)
|
|
399
|
+
['a', 'b', 'c']
|
|
400
|
+
sage: _find_arguments_for_callable(lambda x,y,z=2: x+y+z)
|
|
401
|
+
['x', 'y']
|
|
402
|
+
sage: def f(a, b, c, d=2, e=1): return a+b+c+d+e
|
|
403
|
+
sage: _find_arguments_for_callable(f)
|
|
404
|
+
['a', 'b', 'c']
|
|
405
|
+
sage: g(w,r,t)=w+r+t
|
|
406
|
+
sage: _find_arguments_for_callable(g)
|
|
407
|
+
['w', 'r', 't']
|
|
408
|
+
sage: a,b = var('a,b')
|
|
409
|
+
sage: _find_arguments_for_callable(a+b)
|
|
410
|
+
['a', 'b']
|
|
411
|
+
sage: _find_arguments_for_callable(operator.add)
|
|
412
|
+
[]
|
|
413
|
+
"""
|
|
414
|
+
if is_function_or_cython_function(func):
|
|
415
|
+
pass
|
|
416
|
+
elif hasattr(func, 'arguments'):
|
|
417
|
+
# Might be a symbolic function with arguments
|
|
418
|
+
return [repr(s) for s in func.arguments()]
|
|
419
|
+
else:
|
|
420
|
+
func = func.__call__
|
|
421
|
+
|
|
422
|
+
f_args = sage_getargspec(func)
|
|
423
|
+
if f_args.defaults is None:
|
|
424
|
+
params = f_args.args
|
|
425
|
+
else:
|
|
426
|
+
params = f_args.args[:-len(f_args.defaults)]
|
|
427
|
+
|
|
428
|
+
return params
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
class _ArbitraryCoordinates(_Coordinates):
|
|
432
|
+
"""
|
|
433
|
+
An arbitrary coordinate system.
|
|
434
|
+
"""
|
|
435
|
+
_name = "Arbitrary Coordinates"
|
|
436
|
+
|
|
437
|
+
def __init__(self, custom_trans, dep_var, indep_vars):
|
|
438
|
+
"""
|
|
439
|
+
Initialize an arbitrary coordinate system.
|
|
440
|
+
|
|
441
|
+
INPUT:
|
|
442
|
+
|
|
443
|
+
- ``custom_trans`` -- a 3-tuple of transformation
|
|
444
|
+
functions
|
|
445
|
+
|
|
446
|
+
- ``dep_var`` -- the dependent (function) variable
|
|
447
|
+
|
|
448
|
+
- ``indep_vars`` -- list of the two other independent
|
|
449
|
+
variables
|
|
450
|
+
|
|
451
|
+
EXAMPLES::
|
|
452
|
+
|
|
453
|
+
sage: from sage.plot.plot3d.plot3d import _ArbitraryCoordinates
|
|
454
|
+
sage: x, y, z = var('x y z')
|
|
455
|
+
sage: T = _ArbitraryCoordinates((x + y, x - y, z), z,[x,y])
|
|
456
|
+
sage: f(x, y) = 2*x + y
|
|
457
|
+
sage: T.to_cartesian(f, [x, y])
|
|
458
|
+
(x + y, x - y, 2*x + y)
|
|
459
|
+
sage: [h(1,2) for h in T.to_cartesian(lambda x,y: 2*x+y)]
|
|
460
|
+
[3.0, -1.0, 4.0]
|
|
461
|
+
"""
|
|
462
|
+
self.dep_var = str(dep_var)
|
|
463
|
+
self.indep_vars = [str(i) for i in indep_vars]
|
|
464
|
+
self.custom_trans = tuple(custom_trans)
|
|
465
|
+
|
|
466
|
+
def transform(self, **kwds):
|
|
467
|
+
"""
|
|
468
|
+
EXAMPLES::
|
|
469
|
+
|
|
470
|
+
sage: from sage.plot.plot3d.plot3d import _ArbitraryCoordinates
|
|
471
|
+
sage: x, y, z = var('x y z')
|
|
472
|
+
sage: T = _ArbitraryCoordinates((x + y, x - y, z), x,[y,z])
|
|
473
|
+
|
|
474
|
+
sage: T.transform(x=z,y=1)
|
|
475
|
+
(z + 1, z - 1, z)
|
|
476
|
+
"""
|
|
477
|
+
return tuple(t.subs(**kwds) for t in self.custom_trans)
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
class Spherical(_Coordinates):
|
|
481
|
+
"""
|
|
482
|
+
A spherical coordinate system for use with ``plot3d(transformation=...)``
|
|
483
|
+
where the position of a point is specified by three numbers:
|
|
484
|
+
|
|
485
|
+
- the *radial distance* (``radius``) from the origin
|
|
486
|
+
|
|
487
|
+
- the *azimuth angle* (``azimuth``) from the positive `x`-axis
|
|
488
|
+
|
|
489
|
+
- the *inclination angle* (``inclination``) from the positive `z`-axis
|
|
490
|
+
|
|
491
|
+
These three variables must be specified in the constructor.
|
|
492
|
+
|
|
493
|
+
EXAMPLES:
|
|
494
|
+
|
|
495
|
+
Construct a spherical transformation for a function for the radius
|
|
496
|
+
in terms of the azimuth and inclination::
|
|
497
|
+
|
|
498
|
+
sage: T = Spherical('radius', ['azimuth', 'inclination'])
|
|
499
|
+
|
|
500
|
+
If we construct some concrete variables, we can get a
|
|
501
|
+
transformation in terms of those variables::
|
|
502
|
+
|
|
503
|
+
sage: r, phi, theta = var('r phi theta')
|
|
504
|
+
sage: T.transform(radius=r, azimuth=theta, inclination=phi)
|
|
505
|
+
(r*cos(theta)*sin(phi), r*sin(phi)*sin(theta), r*cos(phi))
|
|
506
|
+
|
|
507
|
+
We can plot with this transform. Remember that the dependent
|
|
508
|
+
variable is the radius, and the independent variables are the
|
|
509
|
+
azimuth and the inclination (in that order)::
|
|
510
|
+
|
|
511
|
+
sage: plot3d(phi * theta, (theta, 0, pi), (phi, 0, 1), transformation=T)
|
|
512
|
+
Graphics3d Object
|
|
513
|
+
|
|
514
|
+
.. PLOT::
|
|
515
|
+
|
|
516
|
+
r, phi, theta = var('r phi theta')
|
|
517
|
+
T = Spherical('radius', ['azimuth', 'inclination'])
|
|
518
|
+
sphinx_plot(plot3d(phi * theta, (theta, 0, pi), (phi, 0, 1), transformation=T))
|
|
519
|
+
|
|
520
|
+
We next graph the function where the inclination angle is constant::
|
|
521
|
+
|
|
522
|
+
sage: S = Spherical('inclination', ['radius', 'azimuth'])
|
|
523
|
+
sage: r, theta = var('r,theta')
|
|
524
|
+
sage: plot3d(3, (r,0,3), (theta, 0, 2*pi), transformation=S)
|
|
525
|
+
Graphics3d Object
|
|
526
|
+
|
|
527
|
+
.. PLOT::
|
|
528
|
+
|
|
529
|
+
S = Spherical('inclination', ['radius', 'azimuth'])
|
|
530
|
+
r, theta = var('r,theta')
|
|
531
|
+
sphinx_plot(plot3d(r-r+3, (r,0,3), (theta, 0, 2*pi), transformation=S))
|
|
532
|
+
|
|
533
|
+
See also :func:`spherical_plot3d` for more examples of plotting in spherical
|
|
534
|
+
coordinates.
|
|
535
|
+
"""
|
|
536
|
+
|
|
537
|
+
def transform(self, radius=None, azimuth=None, inclination=None):
|
|
538
|
+
"""
|
|
539
|
+
A spherical coordinates transform.
|
|
540
|
+
|
|
541
|
+
EXAMPLES::
|
|
542
|
+
|
|
543
|
+
sage: T = Spherical('radius', ['azimuth', 'inclination'])
|
|
544
|
+
sage: T.transform(radius=var('r'), azimuth=var('theta'), inclination=var('phi'))
|
|
545
|
+
(r*cos(theta)*sin(phi), r*sin(phi)*sin(theta), r*cos(phi))
|
|
546
|
+
"""
|
|
547
|
+
return (radius * sin(inclination) * cos(azimuth),
|
|
548
|
+
radius * sin(inclination) * sin(azimuth),
|
|
549
|
+
radius * cos(inclination))
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
class SphericalElevation(_Coordinates):
|
|
553
|
+
"""
|
|
554
|
+
A spherical coordinate system for use with ``plot3d(transformation=...)``
|
|
555
|
+
where the position of a point is specified by three numbers:
|
|
556
|
+
|
|
557
|
+
- the *radial distance* (``radius``) from the origin
|
|
558
|
+
|
|
559
|
+
- the *azimuth angle* (``azimuth``) from the positive `x`-axis
|
|
560
|
+
|
|
561
|
+
- the *elevation angle* (``elevation``) from the `xy`-plane toward the
|
|
562
|
+
positive `z`-axis
|
|
563
|
+
|
|
564
|
+
These three variables must be specified in the constructor.
|
|
565
|
+
|
|
566
|
+
EXAMPLES:
|
|
567
|
+
|
|
568
|
+
Construct a spherical transformation for the radius
|
|
569
|
+
in terms of the azimuth and elevation. Then, get a
|
|
570
|
+
transformation in terms of those variables::
|
|
571
|
+
|
|
572
|
+
sage: T = SphericalElevation('radius', ['azimuth', 'elevation'])
|
|
573
|
+
sage: r, theta, phi = var('r theta phi')
|
|
574
|
+
sage: T.transform(radius=r, azimuth=theta, elevation=phi)
|
|
575
|
+
(r*cos(phi)*cos(theta), r*cos(phi)*sin(theta), r*sin(phi))
|
|
576
|
+
|
|
577
|
+
We can plot with this transform. Remember that the dependent
|
|
578
|
+
variable is the radius, and the independent variables are the
|
|
579
|
+
azimuth and the elevation (in that order)::
|
|
580
|
+
|
|
581
|
+
sage: plot3d(phi * theta, (theta, 0, pi), (phi, 0, 1), transformation=T)
|
|
582
|
+
Graphics3d Object
|
|
583
|
+
|
|
584
|
+
.. PLOT::
|
|
585
|
+
|
|
586
|
+
T = SphericalElevation('radius', ['azimuth', 'elevation'])
|
|
587
|
+
r, theta, phi = var('r theta phi')
|
|
588
|
+
sphinx_plot(plot3d(phi * theta, (theta, 0, pi), (phi, 0, 1), transformation=T))
|
|
589
|
+
|
|
590
|
+
We next graph the function where the elevation angle is constant. This
|
|
591
|
+
should be compared to the similar example for the ``Spherical`` coordinate
|
|
592
|
+
system::
|
|
593
|
+
|
|
594
|
+
sage: SE = SphericalElevation('elevation', ['radius', 'azimuth'])
|
|
595
|
+
sage: r, theta = var('r,theta')
|
|
596
|
+
sage: plot3d(3, (r, 0, 3), (theta, 0, 2*pi), transformation=SE)
|
|
597
|
+
Graphics3d Object
|
|
598
|
+
|
|
599
|
+
.. PLOT::
|
|
600
|
+
|
|
601
|
+
SE = SphericalElevation('elevation', ['radius', 'azimuth'])
|
|
602
|
+
r, theta = var('r,theta')
|
|
603
|
+
sphinx_plot(plot3d(3 + r - r, (r,0,3), (theta, 0, 2*pi), transformation=SE))
|
|
604
|
+
|
|
605
|
+
Plot a sin curve wrapped around the equator::
|
|
606
|
+
|
|
607
|
+
sage: P1 = plot3d((pi/12)*sin(8*theta), (r,0.99,1), (theta, 0, 2*pi),
|
|
608
|
+
....: transformation=SE, plot_points=(10,200))
|
|
609
|
+
sage: P2 = sphere(center=(0,0,0), size=1, color='red', opacity=0.3)
|
|
610
|
+
sage: P1 + P2
|
|
611
|
+
Graphics3d Object
|
|
612
|
+
|
|
613
|
+
.. PLOT::
|
|
614
|
+
|
|
615
|
+
r, theta = var('r,theta')
|
|
616
|
+
SE = SphericalElevation('elevation', ['radius', 'azimuth'])
|
|
617
|
+
P1 = plot3d( (pi/12)*sin(8*theta), (r, 0.99, 1), (theta, 0, 2*pi), transformation=SE, plot_points=(10,200))
|
|
618
|
+
P2 = sphere(center=(0, 0, 0), size=1, color='red', opacity=0.3)
|
|
619
|
+
sphinx_plot(P1 + P2)
|
|
620
|
+
|
|
621
|
+
Now we graph several constant elevation functions alongside several constant
|
|
622
|
+
inclination functions. This example illustrates the difference between the
|
|
623
|
+
``Spherical`` coordinate system and the ``SphericalElevation`` coordinate
|
|
624
|
+
system::
|
|
625
|
+
|
|
626
|
+
sage: r, phi, theta = var('r phi theta')
|
|
627
|
+
sage: SE = SphericalElevation('elevation', ['radius', 'azimuth'])
|
|
628
|
+
sage: angles = [pi/18, pi/12, pi/6]
|
|
629
|
+
sage: P1 = [plot3d(a, (r,0,3), (theta, 0, 2*pi), transformation=SE,
|
|
630
|
+
....: opacity=0.85, color='blue')
|
|
631
|
+
....: for a in angles]
|
|
632
|
+
|
|
633
|
+
sage: S = Spherical('inclination', ['radius', 'azimuth'])
|
|
634
|
+
sage: P2 = [plot3d(a, (r,0,3), (theta, 0, 2*pi), transformation=S,
|
|
635
|
+
....: opacity=0.85, color='red')
|
|
636
|
+
....: for a in angles]
|
|
637
|
+
sage: show(sum(P1+P2), aspect_ratio=1)
|
|
638
|
+
|
|
639
|
+
.. PLOT::
|
|
640
|
+
|
|
641
|
+
r, phi, theta = var('r phi theta')
|
|
642
|
+
SE = SphericalElevation('elevation', ['radius', 'azimuth'])
|
|
643
|
+
S = Spherical('inclination', ['radius', 'azimuth'])
|
|
644
|
+
angles = [pi/18, pi/12, pi/6]
|
|
645
|
+
P1=Graphics()
|
|
646
|
+
P2=Graphics()
|
|
647
|
+
for a in angles:
|
|
648
|
+
P1 += plot3d( a, (r,0,3), (theta, 0, 2*pi), transformation=SE, opacity=0.85, color='blue')
|
|
649
|
+
P2 += plot3d( a, (r,0,3), (theta, 0, 2*pi), transformation=S, opacity=0.85, color='red')
|
|
650
|
+
sphinx_plot(P1+P2)
|
|
651
|
+
|
|
652
|
+
See also :func:`spherical_plot3d` for more examples of plotting in spherical
|
|
653
|
+
coordinates.
|
|
654
|
+
"""
|
|
655
|
+
|
|
656
|
+
def transform(self, radius=None, azimuth=None, elevation=None):
|
|
657
|
+
"""
|
|
658
|
+
A spherical elevation coordinates transform.
|
|
659
|
+
|
|
660
|
+
EXAMPLES::
|
|
661
|
+
|
|
662
|
+
sage: T = SphericalElevation('radius', ['azimuth', 'elevation'])
|
|
663
|
+
sage: T.transform(radius=var('r'), azimuth=var('theta'), elevation=var('phi'))
|
|
664
|
+
(r*cos(phi)*cos(theta), r*cos(phi)*sin(theta), r*sin(phi))
|
|
665
|
+
"""
|
|
666
|
+
return (radius * cos(elevation) * cos(azimuth),
|
|
667
|
+
radius * cos(elevation) * sin(azimuth),
|
|
668
|
+
radius * sin(elevation))
|
|
669
|
+
|
|
670
|
+
|
|
671
|
+
class Cylindrical(_Coordinates):
|
|
672
|
+
"""
|
|
673
|
+
A cylindrical coordinate system for use with ``plot3d(transformation=...)``
|
|
674
|
+
where the position of a point is specified by three numbers:
|
|
675
|
+
|
|
676
|
+
- the *radial distance* (``radius``) from the `z`-axis
|
|
677
|
+
|
|
678
|
+
- the *azimuth angle* (``azimuth``) from the positive `x`-axis
|
|
679
|
+
|
|
680
|
+
- the *height* or *altitude* (``height``) above the `xy`-plane
|
|
681
|
+
|
|
682
|
+
These three variables must be specified in the constructor.
|
|
683
|
+
|
|
684
|
+
EXAMPLES:
|
|
685
|
+
|
|
686
|
+
Construct a cylindrical transformation for a function for ``height`` in terms of
|
|
687
|
+
``radius`` and ``azimuth``::
|
|
688
|
+
|
|
689
|
+
sage: T = Cylindrical('height', ['radius', 'azimuth'])
|
|
690
|
+
|
|
691
|
+
If we construct some concrete variables, we can get a transformation::
|
|
692
|
+
|
|
693
|
+
sage: r, theta, z = var('r theta z')
|
|
694
|
+
sage: T.transform(radius=r, azimuth=theta, height=z)
|
|
695
|
+
(r*cos(theta), r*sin(theta), z)
|
|
696
|
+
|
|
697
|
+
We can plot with this transform. Remember that the dependent
|
|
698
|
+
variable is the height, and the independent variables are the
|
|
699
|
+
radius and the azimuth (in that order)::
|
|
700
|
+
|
|
701
|
+
sage: plot3d(9-r^2, (r, 0, 3), (theta, 0, pi), transformation=T)
|
|
702
|
+
Graphics3d Object
|
|
703
|
+
|
|
704
|
+
.. PLOT::
|
|
705
|
+
|
|
706
|
+
T = Cylindrical('height', ['radius', 'azimuth'])
|
|
707
|
+
r, theta, z = var('r theta z')
|
|
708
|
+
sphinx_plot(plot3d(9 - r**2, (r, 0, 3), (theta, 0, pi), transformation=T))
|
|
709
|
+
|
|
710
|
+
We next graph the function where the radius is constant::
|
|
711
|
+
|
|
712
|
+
sage: S = Cylindrical('radius', ['azimuth', 'height'])
|
|
713
|
+
sage: theta, z = var('theta, z')
|
|
714
|
+
sage: plot3d(3, (theta, 0, 2*pi), (z, -2, 2), transformation=S)
|
|
715
|
+
Graphics3d Object
|
|
716
|
+
|
|
717
|
+
.. PLOT::
|
|
718
|
+
|
|
719
|
+
S = Cylindrical('radius', ['azimuth', 'height'])
|
|
720
|
+
theta, z = var('theta, z')
|
|
721
|
+
sphinx_plot(plot3d(3 + z - z, (theta, 0, 2*pi), (z, -2, 2), transformation=S))
|
|
722
|
+
|
|
723
|
+
See also :func:`cylindrical_plot3d` for more examples of plotting in cylindrical
|
|
724
|
+
coordinates.
|
|
725
|
+
"""
|
|
726
|
+
|
|
727
|
+
def transform(self, radius=None, azimuth=None, height=None):
|
|
728
|
+
"""
|
|
729
|
+
A cylindrical coordinates transform.
|
|
730
|
+
|
|
731
|
+
EXAMPLES::
|
|
732
|
+
|
|
733
|
+
sage: T = Cylindrical('height', ['azimuth', 'radius'])
|
|
734
|
+
sage: T.transform(radius=var('r'), azimuth=var('theta'), height=var('z'))
|
|
735
|
+
(r*cos(theta), r*sin(theta), z)
|
|
736
|
+
"""
|
|
737
|
+
return (radius * cos(azimuth),
|
|
738
|
+
radius * sin(azimuth),
|
|
739
|
+
height)
|
|
740
|
+
|
|
741
|
+
|
|
742
|
+
class TrivialTriangleFactory:
|
|
743
|
+
"""
|
|
744
|
+
Class emulating behavior of :class:`~sage.plot.plot3d.tri_plot.TriangleFactory`
|
|
745
|
+
but simply returning a list of vertices for both regular and
|
|
746
|
+
smooth triangles.
|
|
747
|
+
"""
|
|
748
|
+
def triangle(self, a, b, c, color=None):
|
|
749
|
+
"""
|
|
750
|
+
Function emulating behavior of
|
|
751
|
+
:meth:`~sage.plot.plot3d.tri_plot.TriangleFactory.triangle`
|
|
752
|
+
but simply returning a list of vertices.
|
|
753
|
+
|
|
754
|
+
INPUT:
|
|
755
|
+
|
|
756
|
+
- ``a``, ``b``, ``c`` -- triples (x,y,z) representing corners
|
|
757
|
+
on a triangle in 3-space
|
|
758
|
+
|
|
759
|
+
- ``color`` -- ignored
|
|
760
|
+
|
|
761
|
+
OUTPUT: the list ``[a,b,c]``
|
|
762
|
+
|
|
763
|
+
TESTS::
|
|
764
|
+
|
|
765
|
+
sage: from sage.plot.plot3d.plot3d import TrivialTriangleFactory
|
|
766
|
+
sage: factory = TrivialTriangleFactory()
|
|
767
|
+
sage: tri = factory.triangle([0,0,0],[0,0,1],[1,1,0])
|
|
768
|
+
sage: tri
|
|
769
|
+
[[0, 0, 0], [0, 0, 1], [1, 1, 0]]
|
|
770
|
+
"""
|
|
771
|
+
return [a, b, c]
|
|
772
|
+
|
|
773
|
+
def smooth_triangle(self, a, b, c, da, db, dc, color=None):
|
|
774
|
+
"""
|
|
775
|
+
Function emulating behavior of
|
|
776
|
+
:meth:`~sage.plot.plot3d.tri_plot.TriangleFactory.smooth_triangle`
|
|
777
|
+
but simply returning a list of vertices.
|
|
778
|
+
|
|
779
|
+
INPUT:
|
|
780
|
+
|
|
781
|
+
- ``a``, ``b``, ``c`` -- triples (x,y,z) representing corners
|
|
782
|
+
on a triangle in 3-space
|
|
783
|
+
|
|
784
|
+
- ``da``, ``db``, ``dc`` -- ignored
|
|
785
|
+
|
|
786
|
+
- ``color`` -- ignored
|
|
787
|
+
|
|
788
|
+
OUTPUT: the list ``[a,b,c]``
|
|
789
|
+
|
|
790
|
+
TESTS::
|
|
791
|
+
|
|
792
|
+
sage: from sage.plot.plot3d.plot3d import TrivialTriangleFactory
|
|
793
|
+
sage: factory = TrivialTriangleFactory()
|
|
794
|
+
sage: sm_tri = factory.smooth_triangle([0,0,0],[0,0,1],[1,1,0],[0,0,1],[0,2,0],[1,0,0])
|
|
795
|
+
sage: sm_tri
|
|
796
|
+
[[0, 0, 0], [0, 0, 1], [1, 1, 0]]
|
|
797
|
+
"""
|
|
798
|
+
return [a, b, c]
|
|
799
|
+
|
|
800
|
+
|
|
801
|
+
def plot3d(f, urange, vrange, adaptive=False, transformation=None, **kwds):
|
|
802
|
+
"""
|
|
803
|
+
Plots a function in 3d.
|
|
804
|
+
|
|
805
|
+
INPUT:
|
|
806
|
+
|
|
807
|
+
- ``f`` -- a symbolic expression or function of 2
|
|
808
|
+
variables
|
|
809
|
+
|
|
810
|
+
- ``urange`` -- a 2-tuple (u_min, u_max) or a 3-tuple
|
|
811
|
+
(u, u_min, u_max)
|
|
812
|
+
|
|
813
|
+
- ``vrange`` -- a 2-tuple (v_min, v_max) or a 3-tuple
|
|
814
|
+
(v, v_min, v_max)
|
|
815
|
+
|
|
816
|
+
- ``adaptive`` -- boolean (default: ``False``); whether to use
|
|
817
|
+
adaptive refinement to draw the plot (slower, but may look better).
|
|
818
|
+
This option does NOT work in conjunction with a transformation
|
|
819
|
+
(see below).
|
|
820
|
+
|
|
821
|
+
- ``mesh`` -- boolean (default: ``False``); whether to display
|
|
822
|
+
mesh grid lines
|
|
823
|
+
|
|
824
|
+
- ``dots`` -- boolean (default: ``False``); whether to display
|
|
825
|
+
dots at mesh grid points
|
|
826
|
+
|
|
827
|
+
- ``plot_points`` -- (default: ``'automatic'``) initial number of sample
|
|
828
|
+
points in each direction; an integer or a pair of integers
|
|
829
|
+
|
|
830
|
+
- ``transformation`` -- (default: ``None``) a transformation to
|
|
831
|
+
apply. May be a 3 or 4-tuple (x_func, y_func, z_func,
|
|
832
|
+
independent_vars) where the first 3 items indicate a
|
|
833
|
+
transformation to Cartesian coordinates (from your coordinate
|
|
834
|
+
system) in terms of u, v, and the function variable fvar (for
|
|
835
|
+
which the value of f will be substituted). If a 3-tuple is
|
|
836
|
+
specified, the independent variables are chosen from the range
|
|
837
|
+
variables. If a 4-tuple is specified, the 4th element is a list
|
|
838
|
+
of independent variables. ``transformation`` may also be a
|
|
839
|
+
predefined coordinate system transformation like Spherical or
|
|
840
|
+
Cylindrical.
|
|
841
|
+
|
|
842
|
+
.. NOTE::
|
|
843
|
+
|
|
844
|
+
``mesh`` and ``dots`` are not supported when using the Tachyon
|
|
845
|
+
raytracer renderer.
|
|
846
|
+
|
|
847
|
+
EXAMPLES: We plot a 3d function defined as a Python function::
|
|
848
|
+
|
|
849
|
+
sage: plot3d(lambda x, y: x^2 + y^2, (-2,2), (-2,2))
|
|
850
|
+
Graphics3d Object
|
|
851
|
+
|
|
852
|
+
.. PLOT::
|
|
853
|
+
|
|
854
|
+
sphinx_plot(plot3d(lambda x, y: x**2 + y**2, (-2,2), (-2,2)))
|
|
855
|
+
|
|
856
|
+
We plot the same 3d function but using adaptive refinement::
|
|
857
|
+
|
|
858
|
+
sage: plot3d(lambda x, y: x^2 + y^2, (-2,2), (-2,2), adaptive=True)
|
|
859
|
+
Graphics3d Object
|
|
860
|
+
|
|
861
|
+
.. PLOT::
|
|
862
|
+
|
|
863
|
+
sphinx_plot(plot3d(lambda x, y: x**2 + y**2, (-2,2), (-2,2), adaptive=True))
|
|
864
|
+
|
|
865
|
+
Adaptive refinement but with more points::
|
|
866
|
+
|
|
867
|
+
sage: plot3d(lambda x, y: x^2 + y^2, (-2,2), (-2,2), adaptive=True, initial_depth=5)
|
|
868
|
+
Graphics3d Object
|
|
869
|
+
|
|
870
|
+
.. PLOT::
|
|
871
|
+
|
|
872
|
+
sphinx_plot(plot3d(lambda x, y: x**2 + y**2, (-2,2), (-2,2), adaptive=True, initial_depth=5))
|
|
873
|
+
|
|
874
|
+
We plot some 3d symbolic functions::
|
|
875
|
+
|
|
876
|
+
sage: var('x,y')
|
|
877
|
+
(x, y)
|
|
878
|
+
sage: plot3d(x^2 + y^2, (x,-2,2), (y,-2,2))
|
|
879
|
+
Graphics3d Object
|
|
880
|
+
|
|
881
|
+
.. PLOT::
|
|
882
|
+
|
|
883
|
+
var('x y')
|
|
884
|
+
sphinx_plot(plot3d(x**2 + y**2, (x,-2,2), (y,-2,2)))
|
|
885
|
+
|
|
886
|
+
::
|
|
887
|
+
|
|
888
|
+
sage: plot3d(sin(x*y), (x, -pi, pi), (y, -pi, pi))
|
|
889
|
+
Graphics3d Object
|
|
890
|
+
|
|
891
|
+
.. PLOT::
|
|
892
|
+
|
|
893
|
+
var('x y')
|
|
894
|
+
sphinx_plot(plot3d(sin(x*y), (x, -pi, pi), (y, -pi, pi)))
|
|
895
|
+
|
|
896
|
+
We give a plot with extra sample points::
|
|
897
|
+
|
|
898
|
+
sage: var('x,y')
|
|
899
|
+
(x, y)
|
|
900
|
+
sage: plot3d(sin(x^2 + y^2), (x,-5,5), (y,-5,5), plot_points=200)
|
|
901
|
+
Graphics3d Object
|
|
902
|
+
|
|
903
|
+
.. PLOT::
|
|
904
|
+
|
|
905
|
+
var('x y')
|
|
906
|
+
sphinx_plot(plot3d(sin(x**2 + y**2),(x,-5,5),(y,-5,5), plot_points=200))
|
|
907
|
+
|
|
908
|
+
::
|
|
909
|
+
|
|
910
|
+
sage: plot3d(sin(x^2 + y^2), (x, -5, 5), (y, -5, 5), plot_points=[10, 100])
|
|
911
|
+
Graphics3d Object
|
|
912
|
+
|
|
913
|
+
.. PLOT::
|
|
914
|
+
|
|
915
|
+
var('x y')
|
|
916
|
+
sphinx_plot(plot3d(sin(x**2 + y**2), (x, -5, 5), (y, -5, 5), plot_points=[10,100]))
|
|
917
|
+
|
|
918
|
+
A 3d plot with a mesh::
|
|
919
|
+
|
|
920
|
+
sage: var('x,y')
|
|
921
|
+
(x, y)
|
|
922
|
+
sage: plot3d(sin(x - y)*y*cos(x), (x, -3, 3), (y, -3, 3), mesh=True)
|
|
923
|
+
Graphics3d Object
|
|
924
|
+
|
|
925
|
+
.. PLOT::
|
|
926
|
+
|
|
927
|
+
var('x y')
|
|
928
|
+
sphinx_plot(plot3d(sin(x - y)*y*cos(x), (x, -3, 3), (y, -3, 3), mesh=True))
|
|
929
|
+
|
|
930
|
+
The same with thicker mesh lines (not supported in all viewers)::
|
|
931
|
+
|
|
932
|
+
sage: var('x,y')
|
|
933
|
+
(x, y)
|
|
934
|
+
sage: plot3d(sin(x - y)*y*cos(x), (x, -3, 3), (y, -3, 3), mesh=True,
|
|
935
|
+
....: thickness=2, viewer='threejs')
|
|
936
|
+
Graphics3d Object
|
|
937
|
+
|
|
938
|
+
Two wobby translucent planes::
|
|
939
|
+
|
|
940
|
+
sage: x,y = var('x,y')
|
|
941
|
+
sage: P = plot3d(x + y + sin(x*y), (x, -10, 10), (y, -10, 10),
|
|
942
|
+
....: opacity=0.87, color='blue')
|
|
943
|
+
sage: Q = plot3d(x - 2*y - cos(x*y),(x, -10, 10), (y, -10, 10),
|
|
944
|
+
....: opacity=0.3, color='red')
|
|
945
|
+
sage: P + Q
|
|
946
|
+
Graphics3d Object
|
|
947
|
+
|
|
948
|
+
.. PLOT::
|
|
949
|
+
|
|
950
|
+
x,y = var('x,y')
|
|
951
|
+
P = plot3d(x + y + sin(x*y), (x, -10, 10), (y, -10, 10), opacity=0.87, color='blue')
|
|
952
|
+
Q = plot3d(x - 2*y - cos(x*y),(x, -10, 10), (y, -10, 10), opacity=0.3, color='red')
|
|
953
|
+
sphinx_plot(P + Q)
|
|
954
|
+
|
|
955
|
+
We draw two parametric surfaces and a transparent plane::
|
|
956
|
+
|
|
957
|
+
sage: L = plot3d(lambda x,y: 0, (-5,5), (-5,5), color='lightblue', opacity=0.8)
|
|
958
|
+
sage: P = plot3d(lambda x,y: 4 - x^3 - y^2, (-2,2), (-2,2), color='green')
|
|
959
|
+
sage: Q = plot3d(lambda x,y: x^3 + y^2 - 4, (-2,2), (-2,2), color='orange')
|
|
960
|
+
sage: L + P + Q
|
|
961
|
+
Graphics3d Object
|
|
962
|
+
|
|
963
|
+
.. PLOT::
|
|
964
|
+
|
|
965
|
+
L = plot3d(lambda x,y: 0, (-5,5), (-5,5), color='lightblue', opacity=0.8)
|
|
966
|
+
P = plot3d(lambda x,y: 4 - x**3 - y**2, (-2,2), (-2,2), color='green')
|
|
967
|
+
Q = plot3d(lambda x,y: x**3 + y**2 - 4, (-2,2), (-2,2), color='orange')
|
|
968
|
+
sphinx_plot(L + P + Q)
|
|
969
|
+
|
|
970
|
+
We draw the "Sinus" function (water ripple-like surface)::
|
|
971
|
+
|
|
972
|
+
sage: x, y = var('x y')
|
|
973
|
+
sage: plot3d(sin(pi*(x^2 + y^2))/2, (x, -1, 1), (y, -1, 1))
|
|
974
|
+
Graphics3d Object
|
|
975
|
+
|
|
976
|
+
.. PLOT::
|
|
977
|
+
|
|
978
|
+
x, y = var('x y')
|
|
979
|
+
sphinx_plot(plot3d(sin(pi*(x**2 + y**2))/2, (x, -1, 1), (y, -1, 1)))
|
|
980
|
+
|
|
981
|
+
Hill and valley (flat surface with a bump and a dent)::
|
|
982
|
+
|
|
983
|
+
sage: x, y = var('x y')
|
|
984
|
+
sage: plot3d(4*x*exp(-x^2 - y^2), (x, -2, 2), (y, -2, 2))
|
|
985
|
+
Graphics3d Object
|
|
986
|
+
|
|
987
|
+
.. PLOT::
|
|
988
|
+
|
|
989
|
+
x, y = var('x y')
|
|
990
|
+
sphinx_plot(plot3d( 4*x*exp(-x**2 - y**2), (x, -2, 2), (y, -2, 2)))
|
|
991
|
+
|
|
992
|
+
An example of a transformation::
|
|
993
|
+
|
|
994
|
+
sage: r, phi, z = var('r phi z')
|
|
995
|
+
sage: trans = (r*cos(phi), r*sin(phi), z)
|
|
996
|
+
sage: plot3d(cos(r), (r, 0, 17*pi/2), (phi, 0, 2*pi), transformation=trans, opacity=0.87).show(aspect_ratio=(1,1,2), frame=False)
|
|
997
|
+
|
|
998
|
+
.. PLOT::
|
|
999
|
+
|
|
1000
|
+
r, phi, z = var('r phi z')
|
|
1001
|
+
trans = (r*cos(phi), r*sin(phi), z)
|
|
1002
|
+
P = plot3d(cos(r), (r, 0, 17*pi/2), (phi, 0, 2*pi), transformation=trans, opacity=0.87)
|
|
1003
|
+
P.aspect_ratio([1, 1, 2])
|
|
1004
|
+
sphinx_plot(P)
|
|
1005
|
+
|
|
1006
|
+
An example of a transformation with symbolic vector::
|
|
1007
|
+
|
|
1008
|
+
sage: cylindrical(r, theta, z) = [r*cos(theta), r*sin(theta), z]
|
|
1009
|
+
sage: plot3d(3, (theta, 0, pi/2), (z, 0, pi/2), transformation=cylindrical)
|
|
1010
|
+
Graphics3d Object
|
|
1011
|
+
|
|
1012
|
+
.. PLOT::
|
|
1013
|
+
|
|
1014
|
+
r, theta, z = var('r theta z')
|
|
1015
|
+
cylindrical = (r*cos(theta), r*sin(theta), z)
|
|
1016
|
+
P = plot3d(z-z+3, (theta, 0, pi/2), (z, 0, pi/2), transformation=cylindrical)
|
|
1017
|
+
sphinx_plot(P)
|
|
1018
|
+
|
|
1019
|
+
Many more examples of transformations::
|
|
1020
|
+
|
|
1021
|
+
sage: u, v, w = var('u v w')
|
|
1022
|
+
sage: rectangular=(u,v,w)
|
|
1023
|
+
sage: spherical=(w*cos(u)*sin(v),w*sin(u)*sin(v),w*cos(v))
|
|
1024
|
+
sage: cylindric_radial=(w*cos(u),w*sin(u),v)
|
|
1025
|
+
sage: cylindric_axial=(v*cos(u),v*sin(u),w)
|
|
1026
|
+
sage: parabolic_cylindrical=(w*v,(v^2-w^2)/2,u)
|
|
1027
|
+
|
|
1028
|
+
Plot a constant function of each of these to get an idea of what it does::
|
|
1029
|
+
|
|
1030
|
+
sage: A = plot3d(2,(u,-pi,pi),(v,0,pi),transformation=rectangular,plot_points=[100,100])
|
|
1031
|
+
sage: B = plot3d(2,(u,-pi,pi),(v,0,pi),transformation=spherical,plot_points=[100,100])
|
|
1032
|
+
sage: C = plot3d(2,(u,-pi,pi),(v,0,pi),transformation=cylindric_radial,plot_points=[100,100])
|
|
1033
|
+
sage: D = plot3d(2,(u,-pi,pi),(v,0,pi),transformation=cylindric_axial,plot_points=[100,100])
|
|
1034
|
+
sage: E = plot3d(2,(u,-pi,pi),(v,-pi,pi),transformation=parabolic_cylindrical,plot_points=[100,100])
|
|
1035
|
+
sage: @interact
|
|
1036
|
+
....: def _(which_plot=[A,B,C,D,E]):
|
|
1037
|
+
....: show(which_plot)
|
|
1038
|
+
...Interactive function <function _ at ...> with 1 widget
|
|
1039
|
+
which_plot: Dropdown(description='which_plot', options=(Graphics3d Object, Graphics3d Object, Graphics3d Object, Graphics3d Object, Graphics3d Object), value=Graphics3d Object)
|
|
1040
|
+
|
|
1041
|
+
Now plot a function::
|
|
1042
|
+
|
|
1043
|
+
sage: g=3+sin(4*u)/2+cos(4*v)/2
|
|
1044
|
+
sage: F = plot3d(g,(u,-pi,pi),(v,0,pi),transformation=rectangular,plot_points=[100,100])
|
|
1045
|
+
sage: G = plot3d(g,(u,-pi,pi),(v,0,pi),transformation=spherical,plot_points=[100,100])
|
|
1046
|
+
sage: H = plot3d(g,(u,-pi,pi),(v,0,pi),transformation=cylindric_radial,plot_points=[100,100])
|
|
1047
|
+
sage: I = plot3d(g,(u,-pi,pi),(v,0,pi),transformation=cylindric_axial,plot_points=[100,100])
|
|
1048
|
+
sage: J = plot3d(g,(u,-pi,pi),(v,0,pi),transformation=parabolic_cylindrical,plot_points=[100,100])
|
|
1049
|
+
sage: @interact
|
|
1050
|
+
....: def _(which_plot=[F, G, H, I, J]):
|
|
1051
|
+
....: show(which_plot)
|
|
1052
|
+
...Interactive function <function _ at ...> with 1 widget
|
|
1053
|
+
which_plot: Dropdown(description='which_plot', options=(Graphics3d Object, Graphics3d Object, Graphics3d Object, Graphics3d Object, Graphics3d Object), value=Graphics3d Object)
|
|
1054
|
+
|
|
1055
|
+
TESTS:
|
|
1056
|
+
|
|
1057
|
+
Make sure the transformation plots work::
|
|
1058
|
+
|
|
1059
|
+
sage: show(A + B + C + D + E)
|
|
1060
|
+
sage: show(F + G + H + I + J)
|
|
1061
|
+
|
|
1062
|
+
Listing the same plot variable twice gives an error::
|
|
1063
|
+
|
|
1064
|
+
sage: x, y = var('x y')
|
|
1065
|
+
sage: plot3d( 4*x*exp(-x^2-y^2), (x,-2,2), (x,-2,2))
|
|
1066
|
+
Traceback (most recent call last):
|
|
1067
|
+
...
|
|
1068
|
+
ValueError: range variables should be distinct, but there are duplicates
|
|
1069
|
+
|
|
1070
|
+
Verify that :issue:`7423` is fixed::
|
|
1071
|
+
|
|
1072
|
+
sage: f(x,y)=ln(x)
|
|
1073
|
+
sage: P=plot3d(f,(x,0,1),(y,0,1))
|
|
1074
|
+
sage: P
|
|
1075
|
+
Graphics3d Object
|
|
1076
|
+
"""
|
|
1077
|
+
if transformation is not None:
|
|
1078
|
+
params = None
|
|
1079
|
+
from sage.structure.element import Expression
|
|
1080
|
+
# First, determine the parameters for f (from the first item of urange
|
|
1081
|
+
# and vrange, preferably).
|
|
1082
|
+
if len(urange) == 3 and len(vrange) == 3:
|
|
1083
|
+
params = (urange[0], vrange[0])
|
|
1084
|
+
elif isinstance(f, Expression) and f.is_callable():
|
|
1085
|
+
params = f.variables()
|
|
1086
|
+
|
|
1087
|
+
from sage.modules.vector_callable_symbolic_dense import Vector_callable_symbolic_dense
|
|
1088
|
+
if isinstance(transformation, (tuple, list, Vector_callable_symbolic_dense)):
|
|
1089
|
+
if len(transformation) == 3:
|
|
1090
|
+
if params is None:
|
|
1091
|
+
raise ValueError("must specify independent variable names in the ranges when using generic transformation")
|
|
1092
|
+
indep_vars = params
|
|
1093
|
+
elif len(transformation) == 4:
|
|
1094
|
+
indep_vars = transformation[3]
|
|
1095
|
+
transformation = transformation[0:3]
|
|
1096
|
+
else:
|
|
1097
|
+
raise ValueError("unknown transformation type")
|
|
1098
|
+
# find out which variable is the function variable by
|
|
1099
|
+
# eliminating the parameter variables.
|
|
1100
|
+
all_vars = set(sum([list(s.variables()) for s in transformation], []))
|
|
1101
|
+
dep_var = all_vars - set(indep_vars)
|
|
1102
|
+
if len(dep_var) == 1:
|
|
1103
|
+
dep_var = dep_var.pop()
|
|
1104
|
+
transformation = _ArbitraryCoordinates(transformation, dep_var, indep_vars)
|
|
1105
|
+
else:
|
|
1106
|
+
raise ValueError("unable to determine the function variable in the transform")
|
|
1107
|
+
|
|
1108
|
+
if isinstance(transformation, _Coordinates):
|
|
1109
|
+
R = transformation.to_cartesian(f, params)
|
|
1110
|
+
return parametric_plot3d.parametric_plot3d(R, urange, vrange, **kwds)
|
|
1111
|
+
else:
|
|
1112
|
+
raise ValueError('unknown transformation type')
|
|
1113
|
+
elif adaptive:
|
|
1114
|
+
P = plot3d_adaptive(f, urange, vrange, **kwds)
|
|
1115
|
+
else:
|
|
1116
|
+
arg1 = lambda u, v: u
|
|
1117
|
+
arg2 = lambda u, v: v
|
|
1118
|
+
P = parametric_plot3d.parametric_plot3d((arg1, arg2, f),
|
|
1119
|
+
urange,
|
|
1120
|
+
vrange,
|
|
1121
|
+
**kwds)
|
|
1122
|
+
P.frame_aspect_ratio([1.0, 1.0, 0.5])
|
|
1123
|
+
return P
|
|
1124
|
+
|
|
1125
|
+
|
|
1126
|
+
def plot3d_adaptive(f, x_range, y_range, color='automatic',
|
|
1127
|
+
grad_f=None,
|
|
1128
|
+
max_bend=.5, max_depth=5, initial_depth=4, num_colors=128, **kwds):
|
|
1129
|
+
r"""
|
|
1130
|
+
Adaptive 3d plotting of a function of two variables.
|
|
1131
|
+
|
|
1132
|
+
This is used internally by the plot3d command when the option
|
|
1133
|
+
``adaptive=True`` is given.
|
|
1134
|
+
|
|
1135
|
+
INPUT:
|
|
1136
|
+
|
|
1137
|
+
- ``f`` -- a symbolic function or a Python function of 3 variables
|
|
1138
|
+
|
|
1139
|
+
- ``x_range`` -- x range of values: 2-tuple (xmin,
|
|
1140
|
+
xmax) or 3-tuple (x,xmin,xmax)
|
|
1141
|
+
|
|
1142
|
+
- ``y_range`` -- y range of values: 2-tuple (ymin, ymax) or 3-tuple
|
|
1143
|
+
(y,ymin,ymax)
|
|
1144
|
+
|
|
1145
|
+
- ``grad_f`` -- gradient of f as a Python function
|
|
1146
|
+
|
|
1147
|
+
- ``color`` -- "automatic"; a rainbow of num_colors colors
|
|
1148
|
+
|
|
1149
|
+
- ``num_colors`` -- (default: 128) number of colors to use with default
|
|
1150
|
+
color
|
|
1151
|
+
|
|
1152
|
+
- ``max_bend`` -- (default: 0.5)
|
|
1153
|
+
|
|
1154
|
+
- ``max_depth`` -- (default: 5)
|
|
1155
|
+
|
|
1156
|
+
- ``initial_depth`` -- (default: 4)
|
|
1157
|
+
|
|
1158
|
+
- ``**kwds`` -- standard graphics parameters
|
|
1159
|
+
|
|
1160
|
+
EXAMPLES:
|
|
1161
|
+
|
|
1162
|
+
We plot `\sin(xy)`::
|
|
1163
|
+
|
|
1164
|
+
sage: from sage.plot.plot3d.plot3d import plot3d_adaptive
|
|
1165
|
+
sage: x, y = var('x,y')
|
|
1166
|
+
sage: plot3d_adaptive(sin(x*y), (x, -pi, pi), (y, -pi, pi), initial_depth=5)
|
|
1167
|
+
Graphics3d Object
|
|
1168
|
+
|
|
1169
|
+
.. PLOT::
|
|
1170
|
+
|
|
1171
|
+
from sage.plot.plot3d.plot3d import plot3d_adaptive
|
|
1172
|
+
x, y = var('x,y')
|
|
1173
|
+
sphinx_plot(plot3d_adaptive(sin(x*y), (x,-pi,pi), (y,-pi,pi), initial_depth=5))
|
|
1174
|
+
"""
|
|
1175
|
+
max_depth = max(max_depth, initial_depth)
|
|
1176
|
+
|
|
1177
|
+
from sage.plot.misc import setup_for_eval_on_grid
|
|
1178
|
+
g, ranges = setup_for_eval_on_grid(f, [x_range, y_range], plot_points=2)
|
|
1179
|
+
xmin, xmax = ranges[0][:2]
|
|
1180
|
+
ymin, ymax = ranges[1][:2]
|
|
1181
|
+
|
|
1182
|
+
opacity = float(kwds.get('opacity', 1))
|
|
1183
|
+
|
|
1184
|
+
if color == "automatic":
|
|
1185
|
+
texture = rainbow(num_colors, 'rgbtuple')
|
|
1186
|
+
else:
|
|
1187
|
+
if isinstance(color, list):
|
|
1188
|
+
texture = color
|
|
1189
|
+
else:
|
|
1190
|
+
kwds['color'] = color
|
|
1191
|
+
texture = Texture(kwds)
|
|
1192
|
+
|
|
1193
|
+
factory = TrivialTriangleFactory()
|
|
1194
|
+
plot = TrianglePlot(factory, g, (xmin, xmax), (ymin, ymax), g=grad_f,
|
|
1195
|
+
min_depth=initial_depth, max_depth=max_depth,
|
|
1196
|
+
max_bend=max_bend, num_colors=None)
|
|
1197
|
+
|
|
1198
|
+
P = IndexFaceSet(plot._objects)
|
|
1199
|
+
if isinstance(texture, (list, tuple)):
|
|
1200
|
+
if len(texture) == 2:
|
|
1201
|
+
# do a grid coloring
|
|
1202
|
+
xticks = (xmax - xmin) / 2**initial_depth
|
|
1203
|
+
yticks = (ymax - ymin) / 2**initial_depth
|
|
1204
|
+
parts = P.partition(lambda x, y, z: (int((x - xmin) / xticks) + int((y - ymin) / yticks)) % 2)
|
|
1205
|
+
else:
|
|
1206
|
+
# do a topo coloring
|
|
1207
|
+
bounds = P.bounding_box()
|
|
1208
|
+
min_z = bounds[0][2]
|
|
1209
|
+
max_z = bounds[1][2]
|
|
1210
|
+
if max_z == min_z:
|
|
1211
|
+
span = 0
|
|
1212
|
+
else:
|
|
1213
|
+
span = (len(texture) - 1) / (max_z - min_z) # max to avoid dividing by 0
|
|
1214
|
+
parts = P.partition(lambda x, y, z: int((z - min_z) * span))
|
|
1215
|
+
all = []
|
|
1216
|
+
for k, G in parts.items():
|
|
1217
|
+
G.set_texture(texture[k], opacity=opacity)
|
|
1218
|
+
all.append(G)
|
|
1219
|
+
P = Graphics3dGroup(all)
|
|
1220
|
+
else:
|
|
1221
|
+
P.set_texture(texture)
|
|
1222
|
+
|
|
1223
|
+
P.frame_aspect_ratio([1.0, 1.0, 0.5])
|
|
1224
|
+
P._set_extra_kwds(kwds)
|
|
1225
|
+
return P
|
|
1226
|
+
|
|
1227
|
+
|
|
1228
|
+
def spherical_plot3d(f, urange, vrange, **kwds):
|
|
1229
|
+
"""
|
|
1230
|
+
Plots a function in spherical coordinates. This function is
|
|
1231
|
+
equivalent to::
|
|
1232
|
+
|
|
1233
|
+
sage: r,u,v=var('r,u,v')
|
|
1234
|
+
sage: f=u*v; urange=(u,0,pi); vrange=(v,0,pi)
|
|
1235
|
+
sage: T = (r*cos(u)*sin(v), r*sin(u)*sin(v), r*cos(v), [u,v])
|
|
1236
|
+
sage: plot3d(f, urange, vrange, transformation=T)
|
|
1237
|
+
Graphics3d Object
|
|
1238
|
+
|
|
1239
|
+
or equivalently::
|
|
1240
|
+
|
|
1241
|
+
sage: T = Spherical('radius', ['azimuth', 'inclination'])
|
|
1242
|
+
sage: f=lambda u,v: u*v; urange=(u,0,pi); vrange=(v,0,pi)
|
|
1243
|
+
sage: plot3d(f, urange, vrange, transformation=T)
|
|
1244
|
+
Graphics3d Object
|
|
1245
|
+
|
|
1246
|
+
INPUT:
|
|
1247
|
+
|
|
1248
|
+
- ``f`` -- a symbolic expression or function of two variables
|
|
1249
|
+
|
|
1250
|
+
- ``urange`` -- a 3-tuple (u, u_min, u_max), the domain of the azimuth variable
|
|
1251
|
+
|
|
1252
|
+
- ``vrange`` -- a 3-tuple (v, v_min, v_max), the domain of the inclination variable
|
|
1253
|
+
|
|
1254
|
+
EXAMPLES:
|
|
1255
|
+
|
|
1256
|
+
A sphere of radius 2::
|
|
1257
|
+
|
|
1258
|
+
sage: x,y = var('x,y')
|
|
1259
|
+
sage: spherical_plot3d(2, (x, 0, 2*pi), (y, 0, pi))
|
|
1260
|
+
Graphics3d Object
|
|
1261
|
+
|
|
1262
|
+
.. PLOT::
|
|
1263
|
+
|
|
1264
|
+
x, y = var('x,y')
|
|
1265
|
+
sphinx_plot(spherical_plot3d(x-x+2, (x, 0, 2*pi), (y, 0, pi)))
|
|
1266
|
+
|
|
1267
|
+
The real and imaginary parts of a spherical harmonic with `l=2` and `m=1`::
|
|
1268
|
+
|
|
1269
|
+
sage: phi, theta = var('phi, theta')
|
|
1270
|
+
sage: Y = spherical_harmonic(2, 1, theta, phi)
|
|
1271
|
+
sage: rea = spherical_plot3d(abs(real(Y)), (phi, 0, 2*pi), (theta, 0, pi), color='blue', opacity=0.6)
|
|
1272
|
+
sage: ima = spherical_plot3d(abs(imag(Y)), (phi, 0, 2*pi), (theta, 0, pi), color='red', opacity=0.6)
|
|
1273
|
+
sage: (rea + ima).show(aspect_ratio=1) # long time (4s on sage.math, 2011)
|
|
1274
|
+
|
|
1275
|
+
.. PLOT::
|
|
1276
|
+
|
|
1277
|
+
phi, theta = var('phi, theta')
|
|
1278
|
+
Y = spherical_harmonic(2, 1, theta, phi)
|
|
1279
|
+
rea = spherical_plot3d(abs(real(Y)), (phi, 0, 2*pi), (theta, 0, pi), color='blue', opacity=0.6)
|
|
1280
|
+
ima = spherical_plot3d(abs(imag(Y)), (phi, 0, 2*pi), (theta, 0, pi), color='red', opacity=0.6)
|
|
1281
|
+
sphinx_plot(rea + ima)
|
|
1282
|
+
|
|
1283
|
+
A drop of water::
|
|
1284
|
+
|
|
1285
|
+
sage: x,y = var('x,y')
|
|
1286
|
+
sage: spherical_plot3d(e^-y, (x, 0, 2*pi), (y, 0, pi), opacity=0.5).show(frame=False)
|
|
1287
|
+
|
|
1288
|
+
.. PLOT::
|
|
1289
|
+
|
|
1290
|
+
x, y = var('x,y')
|
|
1291
|
+
sphinx_plot(spherical_plot3d(e**-y, (x, 0, 2*pi), (y, 0, pi), opacity=0.5))
|
|
1292
|
+
|
|
1293
|
+
An object similar to a heart::
|
|
1294
|
+
|
|
1295
|
+
sage: x,y = var('x,y')
|
|
1296
|
+
sage: spherical_plot3d((2 + cos(2*x))*(y + 1), (x, 0, 2*pi), (y, 0, pi), rgbcolor=(1, .1, .1))
|
|
1297
|
+
Graphics3d Object
|
|
1298
|
+
|
|
1299
|
+
.. PLOT::
|
|
1300
|
+
|
|
1301
|
+
x, y = var('x,y')
|
|
1302
|
+
sphinx_plot(spherical_plot3d((2 + cos(2*x))*(y + 1), (x, 0, 2*pi), (y, 0, pi), rgbcolor=(1, .1, .1)))
|
|
1303
|
+
|
|
1304
|
+
Some random figures::
|
|
1305
|
+
|
|
1306
|
+
sage: x,y = var('x,y')
|
|
1307
|
+
sage: spherical_plot3d(1 + sin(5*x)/5, (x, 0, 2*pi), (y, 0, pi), rgbcolor=(1, 0.5, 0), plot_points=(80, 80), opacity=0.7)
|
|
1308
|
+
Graphics3d Object
|
|
1309
|
+
|
|
1310
|
+
.. PLOT::
|
|
1311
|
+
|
|
1312
|
+
x,y = var('x,y')
|
|
1313
|
+
sphinx_plot(spherical_plot3d(1 + sin(5*x)/5, (x, 0, 2*pi), (y, 0, pi), rgbcolor=(1, 0.5, 0), plot_points=(80, 80), opacity=0.7))
|
|
1314
|
+
|
|
1315
|
+
::
|
|
1316
|
+
|
|
1317
|
+
sage: x, y = var('x,y')
|
|
1318
|
+
sage: spherical_plot3d(1 + 2*cos(2*y), (x, 0, 3*pi/2), (y, 0, pi)).show(aspect_ratio=(1, 1, 1))
|
|
1319
|
+
|
|
1320
|
+
.. PLOT::
|
|
1321
|
+
|
|
1322
|
+
x, y = var('x,y')
|
|
1323
|
+
sphinx_plot(spherical_plot3d(1 + 2*cos(2*y), (x, 0, 3*pi/2), (y, 0, pi)))
|
|
1324
|
+
"""
|
|
1325
|
+
return plot3d(f, urange, vrange, transformation=Spherical('radius', ['azimuth', 'inclination']), **kwds)
|
|
1326
|
+
|
|
1327
|
+
|
|
1328
|
+
def cylindrical_plot3d(f, urange, vrange, **kwds):
|
|
1329
|
+
"""
|
|
1330
|
+
Plots a function in cylindrical coordinates. This function is
|
|
1331
|
+
equivalent to::
|
|
1332
|
+
|
|
1333
|
+
sage: r, u, v = var('r,u,v')
|
|
1334
|
+
sage: f = u*v; urange = (u, 0, pi); vrange = (v, 0, pi)
|
|
1335
|
+
sage: T = (r*cos(u), r*sin(u), v, [u, v])
|
|
1336
|
+
sage: plot3d(f, urange, vrange, transformation=T)
|
|
1337
|
+
Graphics3d Object
|
|
1338
|
+
|
|
1339
|
+
.. PLOT::
|
|
1340
|
+
|
|
1341
|
+
r, u, v = var('r,u,v')
|
|
1342
|
+
f = u*v; urange = (u, 0, pi); vrange = (v, 0, pi)
|
|
1343
|
+
T = (r*cos(u), r*sin(u), v, [u,v])
|
|
1344
|
+
sphinx_plot(plot3d(f, urange, vrange, transformation=T))
|
|
1345
|
+
|
|
1346
|
+
or equivalently::
|
|
1347
|
+
|
|
1348
|
+
sage: T = Cylindrical('radius', ['azimuth', 'height'])
|
|
1349
|
+
sage: f=lambda u,v: u*v; urange=(u,0,pi); vrange=(v,0,pi)
|
|
1350
|
+
sage: plot3d(f, urange, vrange, transformation=T)
|
|
1351
|
+
Graphics3d Object
|
|
1352
|
+
|
|
1353
|
+
INPUT:
|
|
1354
|
+
|
|
1355
|
+
- ``f`` -- a symbolic expression or function of two variables,
|
|
1356
|
+
representing the radius from the `z`-axis
|
|
1357
|
+
|
|
1358
|
+
- ``urange`` -- a 3-tuple (u, u_min, u_max), the domain of the
|
|
1359
|
+
azimuth variable
|
|
1360
|
+
|
|
1361
|
+
- ``vrange`` -- a 3-tuple (v, v_min, v_max), the domain of the
|
|
1362
|
+
elevation (`z`) variable
|
|
1363
|
+
|
|
1364
|
+
EXAMPLES:
|
|
1365
|
+
|
|
1366
|
+
A portion of a cylinder of radius 2::
|
|
1367
|
+
|
|
1368
|
+
sage: theta, z = var('theta,z')
|
|
1369
|
+
sage: cylindrical_plot3d(2, (theta, 0, 3*pi/2), (z, -2, 2))
|
|
1370
|
+
Graphics3d Object
|
|
1371
|
+
|
|
1372
|
+
.. PLOT::
|
|
1373
|
+
|
|
1374
|
+
theta, z = var('theta,z')
|
|
1375
|
+
sphinx_plot(cylindrical_plot3d(z-z+2, (theta, 0, 3*pi/2), (z, -2, 2)))
|
|
1376
|
+
|
|
1377
|
+
Some random figures:
|
|
1378
|
+
|
|
1379
|
+
::
|
|
1380
|
+
|
|
1381
|
+
sage: cylindrical_plot3d(cosh(z), (theta, 0, 2*pi), (z, -2, 2))
|
|
1382
|
+
Graphics3d Object
|
|
1383
|
+
|
|
1384
|
+
.. PLOT::
|
|
1385
|
+
|
|
1386
|
+
theta, z = var('theta,z')
|
|
1387
|
+
sphinx_plot(cylindrical_plot3d(cosh(z), (theta, 0, 2*pi), (z, -2, 2)))
|
|
1388
|
+
|
|
1389
|
+
::
|
|
1390
|
+
|
|
1391
|
+
sage: cylindrical_plot3d(e^(-z^2)*(cos(4*theta) + 2) + 1, (theta, 0, 2*pi), (z, -2, 2), plot_points=[80, 80]).show(aspect_ratio=(1, 1, 1))
|
|
1392
|
+
|
|
1393
|
+
.. PLOT::
|
|
1394
|
+
|
|
1395
|
+
theta, z = var('theta,z')
|
|
1396
|
+
P = cylindrical_plot3d(e**(-z**2)*(cos(4*theta) + 2) + 1, (theta, 0, 2*pi), (z, -2, 2), plot_points=[80, 80])
|
|
1397
|
+
P.aspect_ratio([1, 1, 1])
|
|
1398
|
+
sphinx_plot(P)
|
|
1399
|
+
"""
|
|
1400
|
+
return plot3d(f, urange, vrange, transformation=Cylindrical('radius', ['azimuth', 'height']), **kwds)
|
|
1401
|
+
|
|
1402
|
+
|
|
1403
|
+
def axes(scale=1, radius=None, **kwds):
|
|
1404
|
+
"""
|
|
1405
|
+
Create basic axes in three dimensions. Each axis is a three
|
|
1406
|
+
dimensional arrow object.
|
|
1407
|
+
|
|
1408
|
+
INPUT:
|
|
1409
|
+
|
|
1410
|
+
- ``scale`` -- (default: 1) the length of the axes (all three will be the
|
|
1411
|
+
same)
|
|
1412
|
+
|
|
1413
|
+
- ``radius`` -- (default: .01) the radius of the axes as arrows
|
|
1414
|
+
|
|
1415
|
+
EXAMPLES::
|
|
1416
|
+
|
|
1417
|
+
sage: from sage.plot.plot3d.plot3d import axes
|
|
1418
|
+
sage: S = axes(6, color='black'); S
|
|
1419
|
+
Graphics3d Object
|
|
1420
|
+
|
|
1421
|
+
.. PLOT::
|
|
1422
|
+
|
|
1423
|
+
from sage.plot.plot3d.plot3d import axes
|
|
1424
|
+
S = axes(6, color='black')
|
|
1425
|
+
sphinx_plot(S)
|
|
1426
|
+
|
|
1427
|
+
::
|
|
1428
|
+
|
|
1429
|
+
sage: T = axes(2, .5); T
|
|
1430
|
+
Graphics3d Object
|
|
1431
|
+
|
|
1432
|
+
.. PLOT::
|
|
1433
|
+
|
|
1434
|
+
from sage.plot.plot3d.plot3d import axes
|
|
1435
|
+
T = axes(2, .5)
|
|
1436
|
+
sphinx_plot(T)
|
|
1437
|
+
"""
|
|
1438
|
+
if radius is None:
|
|
1439
|
+
radius = scale / 100.0
|
|
1440
|
+
return Graphics3dGroup([arrow3d((0, 0, 0), (scale, 0, 0), radius, **kwds),
|
|
1441
|
+
arrow3d((0, 0, 0), (0, scale, 0), radius, **kwds),
|
|
1442
|
+
arrow3d((0, 0, 0), (0, 0, scale), radius, **kwds)])
|