Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/plot/plot3d/parametric_plot3d.py
4038 views
1
"""
2
Parametric Plots
3
"""
4
5
from parametric_surface import ParametricSurface
6
from shapes2 import line3d
7
from sage.misc.misc import xsrange, srange
8
from sage.structure.element import is_Vector
9
10
from sage.ext.fast_eval import fast_float, fast_float_constant
11
12
def parametric_plot3d(f, urange, vrange=None, plot_points="automatic", boundary_style=None, **kwds):
13
r"""
14
Return a parametric three-dimensional space curve or surface.
15
16
There are four ways to call this function:
17
18
- ``parametric_plot3d([f_x, f_y, f_z], (u_min,
19
u_max))``:
20
`f_x, f_y, f_z` are three functions and
21
`u_{\min}` and `u_{\max}` are real numbers
22
23
- ``parametric_plot3d([f_x, f_y, f_z], (u, u_min,
24
u_max))``:
25
`f_x, f_y, f_z` can be viewed as functions of
26
`u`
27
28
- ``parametric_plot3d([f_x, f_y, f_z], (u_min, u_max),
29
(v_min, v_max))``:
30
`f_x, f_y, f_z` are each functions of two variables
31
32
- ``parametric_plot3d([f_x, f_y, f_z], (u, u_min,
33
u_max), (v, v_min, v_max))``:
34
`f_x, f_y, f_z` can be viewed as functions of
35
`u` and `v`
36
37
38
INPUT:
39
40
- ``f`` - a 3-tuple of functions or expressions, or vector of size 3
41
42
- ``urange`` - a 2-tuple (u_min, u_max) or a 3-tuple
43
(u, u_min, u_max)
44
45
- ``vrange`` - (optional - only used for surfaces) a
46
2-tuple (v_min, v_max) or a 3-tuple (v, v_min, v_max)
47
48
- ``plot_points`` - (default: "automatic", which is
49
75 for curves and [40,40] for surfaces) initial number of sample
50
points in each parameter; an integer for a curve, and a pair of
51
integers for a surface.
52
53
- ``boundary_style`` - (default: None, no boundary) a dict that describes
54
how to draw the boundaries of regions by giving options that are passed
55
to the line3d command.
56
57
- ``mesh`` - bool (default: False) whether to display
58
mesh grid lines
59
60
- ``dots`` - bool (default: False) whether to display
61
dots at mesh grid points
62
63
.. note::
64
65
#. By default for a curve any points where `f_x`,
66
`f_y`, or `f_z` do not evaluate to a real number
67
are skipped.
68
69
#. Currently for a surface `f_x`, `f_y`, and
70
`f_z` have to be defined everywhere. This will change.
71
72
#. mesh and dots are not supported when using the Tachyon ray tracer
73
renderer.
74
75
76
EXAMPLES: We demonstrate each of the four ways to call this
77
function.
78
79
80
#. A space curve defined by three functions of 1 variable:
81
82
::
83
84
sage: parametric_plot3d( (sin, cos, lambda u: u/10), (0, 20))
85
86
Note above the lambda function, which creates a callable Python
87
function that sends `u` to `u/10`.
88
89
#. Next we draw the same plot as above, but using symbolic
90
functions:
91
92
::
93
94
sage: u = var('u')
95
sage: parametric_plot3d( (sin(u), cos(u), u/10), (u, 0, 20))
96
97
#. We draw a parametric surface using 3 Python functions (defined
98
using lambda):
99
100
::
101
102
sage: f = (lambda u,v: cos(u), lambda u,v: sin(u)+cos(v), lambda u,v: sin(v))
103
sage: parametric_plot3d(f, (0, 2*pi), (-pi, pi))
104
105
#. The surface, but with a mesh:
106
107
::
108
109
sage: u, v = var('u,v')
110
sage: parametric_plot3d((cos(u), sin(u) + cos(v), sin(v)), (u, 0, 2*pi), (v, -pi, pi), mesh=True)
111
112
#. The same surface, but where the defining functions are
113
symbolic:
114
115
::
116
117
sage: u, v = var('u,v')
118
sage: parametric_plot3d((cos(u), sin(u) + cos(v), sin(v)), (u, 0, 2*pi), (v, -pi, pi))
119
120
We increase the number of plot points, and make the surface green
121
and transparent:
122
123
::
124
125
sage: parametric_plot3d((cos(u), sin(u) + cos(v), sin(v)), (u, 0, 2*pi), (v, -pi, pi), color='green', opacity=0.1, plot_points=[30,30])
126
127
128
We call the space curve function but with polynomials instead of
129
symbolic variables.
130
131
::
132
133
sage: R.<t> = RDF[]
134
sage: parametric_plot3d( (t, t^2, t^3), (t, 0, 3) )
135
136
Next we plot the same curve, but because we use (0, 3) instead of
137
(t, 0, 3), each polynomial is viewed as a callable function of one
138
variable::
139
140
sage: parametric_plot3d( (t, t^2, t^3), (0, 3) )
141
142
We do a plot but mix a symbolic input, and an integer::
143
144
sage: t = var('t')
145
sage: parametric_plot3d( (1, sin(t), cos(t)), (t, 0, 3) )
146
147
We specify a boundary style to show us the values of the function at its
148
extrema::
149
150
sage: u, v = var('u,v')
151
sage: parametric_plot3d((cos(u), sin(u) + cos(v), sin(v)), (u, 0, pi), (v, 0, pi), \
152
... boundary_style={"color": "black", "thickness": 2})
153
154
We can plot vectors::
155
156
sage: x,y=var('x,y')
157
sage: parametric_plot3d(vector([x-y,x*y,x*cos(y)]), (x,0,2), (y,0,2))
158
sage: t=var('t')
159
sage: p=vector([1,2,3])
160
sage: q=vector([2,-1,2])
161
sage: parametric_plot3d(p*t+q, (t, 0, 2))
162
163
164
Any options you would normally use to specify the appearance of a curve are
165
valid as entries in the boundary_style dict.
166
167
MANY MORE EXAMPLES:
168
169
We plot two interlinked tori::
170
171
sage: u, v = var('u,v')
172
sage: f1 = (4+(3+cos(v))*sin(u), 4+(3+cos(v))*cos(u), 4+sin(v))
173
sage: f2 = (8+(3+cos(v))*cos(u), 3+sin(v), 4+(3+cos(v))*sin(u))
174
sage: p1 = parametric_plot3d(f1, (u,0,2*pi), (v,0,2*pi), texture="red")
175
sage: p2 = parametric_plot3d(f2, (u,0,2*pi), (v,0,2*pi), texture="blue")
176
sage: p1 + p2
177
178
A cylindrical Star of David::
179
180
sage: u,v = var('u v')
181
sage: f_x = cos(u)*cos(v)*(abs(cos(3*v/4))^500 + abs(sin(3*v/4))^500)^(-1/260)*(abs(cos(4*u/4))^200 + abs(sin(4*u/4))^200)^(-1/200)
182
sage: f_y = cos(u)*sin(v)*(abs(cos(3*v/4))^500 + abs(sin(3*v/4))^500)^(-1/260)*(abs(cos(4*u/4))^200 + abs(sin(4*u/4))^200)^(-1/200)
183
sage: f_z = sin(u)*(abs(cos(4*u/4))^200 + abs(sin(4*u/4))^200)^(-1/200)
184
sage: parametric_plot3d([f_x, f_y, f_z], (u, -pi, pi), (v, 0, 2*pi))
185
186
Double heart::
187
188
sage: u, v = var('u,v')
189
sage: f_x = ( abs(v) - abs(u) - abs(tanh((1/sqrt(2))*u)/(1/sqrt(2))) + abs(tanh((1/sqrt(2))*v)/(1/sqrt(2))) )*sin(v)
190
sage: f_y = ( abs(v) - abs(u) - abs(tanh((1/sqrt(2))*u)/(1/sqrt(2))) - abs(tanh((1/sqrt(2))*v)/(1/sqrt(2))) )*cos(v)
191
sage: f_z = sin(u)*(abs(cos(4*u/4))^1 + abs(sin(4*u/4))^1)^(-1/1)
192
sage: parametric_plot3d([f_x, f_y, f_z], (u, 0, pi), (v, -pi, pi))
193
194
Heart::
195
196
sage: u, v = var('u,v')
197
sage: f_x = cos(u)*(4*sqrt(1-v^2)*sin(abs(u))^abs(u))
198
sage: f_y = sin(u) *(4*sqrt(1-v^2)*sin(abs(u))^abs(u))
199
sage: f_z = v
200
sage: parametric_plot3d([f_x, f_y, f_z], (u, -pi, pi), (v, -1, 1), frame=False, color="red")
201
202
Green bowtie::
203
204
sage: u, v = var('u,v')
205
sage: f_x = sin(u) / (sqrt(2) + sin(v))
206
sage: f_y = sin(u) / (sqrt(2) + cos(v))
207
sage: f_z = cos(u) / (1 + sqrt(2))
208
sage: parametric_plot3d([f_x, f_y, f_z], (u, -pi, pi), (v, -pi, pi), frame=False, color="green")
209
210
Boy's surface http://en.wikipedia.org/wiki/Boy's_surface
211
212
::
213
214
sage: u, v = var('u,v')
215
sage: fx = 2/3* (cos(u)* cos(2*v) + sqrt(2)* sin(u)* cos(v))* cos(u) / (sqrt(2) - sin(2*u)* sin(3*v))
216
sage: fy = 2/3* (cos(u)* sin(2*v) - sqrt(2)* sin(u)* sin(v))* cos(u) / (sqrt(2) - sin(2*u)* sin(3*v))
217
sage: fz = sqrt(2)* cos(u)* cos(u) / (sqrt(2) - sin(2*u)* sin(3*v))
218
sage: parametric_plot3d([fx, fy, fz], (u, -2*pi, 2*pi), (v, 0, pi), plot_points = [90,90], frame=False, color="orange") # long time -- about 30 seconds
219
220
Maeder's_Owl (pretty but can't find an internet reference)::
221
222
sage: u, v = var('u,v')
223
sage: fx = v *cos(u) - 0.5* v^2 * cos(2* u)
224
sage: fy = -v *sin(u) - 0.5* v^2 * sin(2* u)
225
sage: fz = 4 *v^1.5 * cos(3 *u / 2) / 3
226
sage: parametric_plot3d([fx, fy, fz], (u, -2*pi, 2*pi), (v, 0, 1),plot_points = [90,90], frame=False, color="purple")
227
228
Bracelet::
229
230
sage: u, v = var('u,v')
231
sage: fx = (2 + 0.2*sin(2*pi*u))*sin(pi*v)
232
sage: fy = 0.2*cos(2*pi*u) *3*cos(2*pi*v)
233
sage: fz = (2 + 0.2*sin(2*pi*u))*cos(pi*v)
234
sage: parametric_plot3d([fx, fy, fz], (u, 0, pi/2), (v, 0, 3*pi/4), frame=False, color="gray")
235
236
Green goblet
237
238
::
239
240
sage: u, v = var('u,v')
241
sage: fx = cos(u)*cos(2*v)
242
sage: fy = sin(u)*cos(2*v)
243
sage: fz = sin(v)
244
sage: parametric_plot3d([fx, fy, fz], (u, 0, 2*pi), (v, 0, pi), frame=False, color="green")
245
246
Funny folded surface - with square projection::
247
248
sage: u, v = var('u,v')
249
sage: fx = cos(u)*sin(2*v)
250
sage: fy = sin(u)*cos(2*v)
251
sage: fz = sin(v)
252
sage: parametric_plot3d([fx, fy, fz], (u, 0, 2*pi), (v, 0, 2*pi), frame=False, color="green")
253
254
Surface of revolution of figure 8::
255
256
sage: u, v = var('u,v')
257
sage: fx = cos(u)*sin(2*v)
258
sage: fy = sin(u)*sin(2*v)
259
sage: fz = sin(v)
260
sage: parametric_plot3d([fx, fy, fz], (u, 0, 2*pi), (v, 0, 2*pi), frame=False, color="green")
261
262
Yellow Whitney's umbrella
263
http://en.wikipedia.org/wiki/Whitney_umbrella::
264
265
sage: u, v = var('u,v')
266
sage: fx = u*v
267
sage: fy = u
268
sage: fz = v^2
269
sage: parametric_plot3d([fx, fy, fz], (u, -1, 1), (v, -1, 1), frame=False, color="yellow")
270
271
Cross cap http://en.wikipedia.org/wiki/Cross-cap::
272
273
sage: u, v = var('u,v')
274
sage: fx = (1+cos(v))*cos(u)
275
sage: fy = (1+cos(v))*sin(u)
276
sage: fz = -tanh((2/3)*(u-pi))*sin(v)
277
sage: parametric_plot3d([fx, fy, fz], (u, 0, 2*pi), (v, 0, 2*pi), frame=False, color="red")
278
279
Twisted torus::
280
281
sage: u, v = var('u,v')
282
sage: fx = (3+sin(v)+cos(u))*cos(2*v)
283
sage: fy = (3+sin(v)+cos(u))*sin(2*v)
284
sage: fz = sin(u)+2*cos(v)
285
sage: parametric_plot3d([fx, fy, fz], (u, 0, 2*pi), (v, 0, 2*pi), frame=False, color="red")
286
287
Four intersecting discs::
288
289
sage: u, v = var('u,v')
290
sage: fx = v *cos(u) -0.5*v^2*cos(2*u)
291
sage: fy = -v*sin(u) -0.5*v^2*sin(2*u)
292
sage: fz = 4* v^1.5 *cos(3* u / 2) / 3
293
sage: parametric_plot3d([fx, fy, fz], (u, 0, 4*pi), (v, 0,2*pi), frame=False, color="red", opacity=0.7)
294
295
Steiner surface/Roman's surface (see
296
http://en.wikipedia.org/wiki/Roman_surface and
297
http://en.wikipedia.org/wiki/Steiner_surface)::
298
299
sage: u, v = var('u,v')
300
sage: fx = (sin(2 * u) * cos(v) * cos(v))
301
sage: fy = (sin(u) * sin(2 * v))
302
sage: fz = (cos(u) * sin(2 * v))
303
sage: parametric_plot3d([fx, fy, fz], (u, -pi/2, pi/2), (v, -pi/2,pi/2), frame=False, color="red")
304
305
Klein bottle? (see http://en.wikipedia.org/wiki/Klein_bottle)::
306
307
sage: u, v = var('u,v')
308
sage: fx = (3*(1+sin(v)) + 2*(1-cos(v)/2)*cos(u))*cos(v)
309
sage: fy = (4+2*(1-cos(v)/2)*cos(u))*sin(v)
310
sage: fz = -2*(1-cos(v)/2) * sin(u)
311
sage: parametric_plot3d([fx, fy, fz], (u, 0, 2*pi), (v, 0, 2*pi), frame=False, color="green")
312
313
A Figure 8 embedding of the Klein bottle (see
314
http://en.wikipedia.org/wiki/Klein_bottle)::
315
316
sage: u, v = var('u,v')
317
sage: fx = (2 + cos(v/2)* sin(u) - sin(v/2)* sin(2 *u))* cos(v)
318
sage: fy = (2 + cos(v/2)* sin(u) - sin(v/2)* sin(2 *u))* sin(v)
319
sage: fz = sin(v/2)* sin(u) + cos(v/2) *sin(2* u)
320
sage: parametric_plot3d([fx, fy, fz], (u, 0, 2*pi), (v, 0, 2*pi), frame=False, color="red")
321
322
Enneper's surface (see
323
http://en.wikipedia.org/wiki/Enneper_surface)::
324
325
sage: u, v = var('u,v')
326
sage: fx = u -u^3/3 + u*v^2
327
sage: fy = v -v^3/3 + v*u^2
328
sage: fz = u^2 - v^2
329
sage: parametric_plot3d([fx, fy, fz], (u, -2, 2), (v, -2, 2), frame=False, color="red")
330
331
Henneberg's surface (see
332
http://xahlee.org/surface/gallery_m.html)
333
334
::
335
336
sage: u, v = var('u,v')
337
sage: fx = 2*sinh(u)*cos(v) -(2/3)*sinh(3*u)*cos(3*v)
338
sage: fy = 2*sinh(u)*sin(v) +(2/3)*sinh(3*u)*sin(3*v)
339
sage: fz = 2*cosh(2*u)*cos(2*v)
340
sage: parametric_plot3d([fx, fy, fz], (u, -1, 1), (v, -pi/2, pi/2), frame=False, color="red")
341
342
Dini's spiral
343
344
::
345
346
sage: u, v = var('u,v')
347
sage: fx = cos(u)*sin(v)
348
sage: fy = sin(u)*sin(v)
349
sage: fz = (cos(v)+log(tan(v/2))) + 0.2*u
350
sage: parametric_plot3d([fx, fy, fz], (u, 0, 12.4), (v, 0.1, 2),frame=False, color="red")
351
352
Catalan's surface (see
353
http://xahlee.org/surface/catalan/catalan.html)::
354
355
sage: u, v = var('u,v')
356
sage: fx = u-sin(u)*cosh(v)
357
sage: fy = 1-cos(u)*cosh(v)
358
sage: fz = 4*sin(1/2*u)*sinh(v/2)
359
sage: parametric_plot3d([fx, fy, fz], (u, -pi, 3*pi), (v, -2, 2), frame=False, color="red")
360
361
A Conchoid::
362
363
sage: u, v = var('u,v')
364
sage: k = 1.2; k_2 = 1.2; a = 1.5
365
sage: f = (k^u*(1+cos(v))*cos(u), k^u*(1+cos(v))*sin(u), k^u*sin(v)-a*k_2^u)
366
sage: parametric_plot3d(f, (u,0,6*pi), (v,0,2*pi), plot_points=[40,40], texture=(0,0.5,0))
367
368
A Mobius strip::
369
370
sage: u,v = var("u,v")
371
sage: parametric_plot3d([cos(u)*(1+v*cos(u/2)), sin(u)*(1+v*cos(u/2)), 0.2*v*sin(u/2)], (u,0, 4*pi+0.5), (v,0, 0.3),plot_points=[50,50])
372
373
A Twisted Ribbon
374
375
::
376
377
sage: u, v = var('u,v')
378
sage: parametric_plot3d([3*sin(u)*cos(v), 3*sin(u)*sin(v), cos(v)], (u,0, 2*pi), (v, 0, pi),plot_points=[50,50])
379
380
An Ellipsoid::
381
382
sage: u, v = var('u,v')
383
sage: parametric_plot3d([3*sin(u)*cos(v), 2*sin(u)*sin(v), cos(u)], (u,0, 2*pi), (v, 0, 2*pi),plot_points=[50,50], aspect_ratio=[1,1,1])
384
385
A Cone::
386
387
sage: u, v = var('u,v')
388
sage: parametric_plot3d([u*cos(v), u*sin(v), u], (u, -1, 1), (v, 0, 2*pi+0.5), plot_points=[50,50])
389
390
A Paraboloid::
391
392
sage: u, v = var('u,v')
393
sage: parametric_plot3d([u*cos(v), u*sin(v), u^2], (u, 0, 1), (v, 0, 2*pi+0.4), plot_points=[50,50])
394
395
A Hyperboloid::
396
397
sage: u, v = var('u,v')
398
sage: plot3d(u^2-v^2, (u, -1, 1), (v, -1, 1), plot_points=[50,50])
399
400
A weird looking surface - like a Mobius band but also an O::
401
402
sage: u, v = var('u,v')
403
sage: parametric_plot3d([sin(u)*cos(u)*log(u^2)*sin(v), (u^2)^(1/6)*(cos(u)^2)^(1/4)*cos(v), sin(v)], (u, 0.001, 1), (v, -pi, pi+0.2), plot_points=[50,50])
404
405
A heart, but not a cardioid (for my wife)::
406
407
sage: u, v = var('u,v')
408
sage: p1 = parametric_plot3d([sin(u)*cos(u)*log(u^2)*v*(1-v)/2, ((u^6)^(1/20)*(cos(u)^2)^(1/4)-1/2)*v*(1-v), v^(0.5)], (u, 0.001, 1), (v, 0, 1), plot_points=[70,70], color='red')
409
sage: p2 = parametric_plot3d([-sin(u)*cos(u)*log(u^2)*v*(1-v)/2, ((u^6)^(1/20)*(cos(u)^2)^(1/4)-1/2)*v*(1-v), v^(0.5)], (u, 0.001, 1), (v, 0, 1), plot_points=[70,70], color='red')
410
sage: show(p1+p2, frame=False)
411
412
A Hyperhelicoidal::
413
414
sage: u = var("u")
415
sage: v = var("v")
416
sage: fx = (sinh(v)*cos(3*u))/(1+cosh(u)*cosh(v))
417
sage: fy = (sinh(v)*sin(3*u))/(1+cosh(u)*cosh(v))
418
sage: fz = (cosh(v)*sinh(u))/(1+cosh(u)*cosh(v))
419
sage: parametric_plot3d([fx, fy, fz], (u, -pi, pi), (v, -pi, pi), plot_points = [50,50], frame=False, color="red")
420
421
A Helicoid (lines through a helix,
422
http://en.wikipedia.org/wiki/Helix)::
423
424
sage: u, v = var('u,v')
425
sage: fx = sinh(v)*sin(u)
426
sage: fy = -sinh(v)*cos(u)
427
sage: fz = 3*u
428
sage: parametric_plot3d([fx, fy, fz], (u, -pi, pi), (v, -pi, pi), plot_points = [50,50], frame=False, color="red")
429
430
Kuen's surface
431
(http://www.math.umd.edu/research/bianchi/Gifccsurfs/ccsurfs.html)::
432
433
sage: fx = (2*(cos(u) + u*sin(u))*sin(v))/(1+ u^2*sin(v)^2)
434
sage: fy = (2*(sin(u) - u*cos(u))*sin(v))/(1+ u^2*sin(v)^2)
435
sage: fz = log(tan(1/2 *v)) + (2*cos(v))/(1+ u^2*sin(v)^2)
436
sage: parametric_plot3d([fx, fy, fz], (u, 0, 2*pi), (v, 0.01, pi-0.01), plot_points = [50,50], frame=False, color="green")
437
438
A 5-pointed star::
439
440
sage: fx = cos(u)*cos(v)*(abs(cos(1*u/4))^0.5 + abs(sin(1*u/4))^0.5)^(-1/0.3)*(abs(cos(5*v/4))^1.7 + abs(sin(5*v/4))^1.7)^(-1/0.1)
441
sage: fy = cos(u)*sin(v)*(abs(cos(1*u/4))^0.5 + abs(sin(1*u/4))^0.5)^(-1/0.3)*(abs(cos(5*v/4))^1.7 + abs(sin(5*v/4))^1.7)^(-1/0.1)
442
sage: fz = sin(u)*(abs(cos(1*u/4))^0.5 + abs(sin(1*u/4))^0.5)^(-1/0.3)
443
sage: parametric_plot3d([fx, fy, fz], (u, -pi/2, pi/2), (v, 0, 2*pi), plot_points = [50,50], frame=False, color="green")
444
445
A cool self-intersecting surface (Eppener surface?)::
446
447
sage: fx = u - u^3/3 + u*v^2
448
sage: fy = v - v^3/3 + v*u^2
449
sage: fz = u^2 - v^2
450
sage: parametric_plot3d([fx, fy, fz], (u, -25, 25), (v, -25, 25), plot_points = [50,50], frame=False, color="green")
451
452
The breather surface
453
(http://en.wikipedia.org/wiki/Breather_surface)::
454
455
sage: fx = (2*sqrt(0.84)*cosh(0.4*u)*(-(sqrt(0.84)*cos(v)*cos(sqrt(0.84)*v)) - sin(v)*sin(sqrt(0.84)*v)))/(0.4*((sqrt(0.84)*cosh(0.4*u))^2 + (0.4*sin(sqrt(0.84)*v))^2))
456
sage: fy = (2*sqrt(0.84)*cosh(0.4*u)*(-(sqrt(0.84)*sin(v)*cos(sqrt(0.84)*v)) + cos(v)*sin(sqrt(0.84)*v)))/(0.4*((sqrt(0.84)*cosh(0.4*u))^2 + (0.4*sin(sqrt(0.84)*v))^2))
457
sage: fz = -u + (2*0.84*cosh(0.4*u)*sinh(0.4*u))/(0.4*((sqrt(0.84)*cosh(0.4*u))^2 + (0.4*sin(sqrt(0.84)*v))^2))
458
sage: parametric_plot3d([fx, fy, fz], (u, -13.2, 13.2), (v, -37.4, 37.4), plot_points = [90,90], frame=False, color="green")
459
460
TESTS::
461
462
sage: u, v = var('u,v')
463
sage: plot3d(u^2-v^2, (u, -1, 1), (u, -1, 1))
464
Traceback (most recent call last):
465
...
466
ValueError: range variables should be distinct, but there are duplicates
467
468
469
From Trac #2858::
470
471
sage: parametric_plot3d((u,-u,v), (u,-10,10),(v,-10,10))
472
sage: f(u)=u; g(v)=v^2; parametric_plot3d((g,f,f), (-10,10),(-10,10))
473
474
From Trac #5368::
475
476
sage: x, y = var('x,y')
477
sage: plot3d(x*y^2 - sin(x), (x,-1,1), (y,-1,1))
478
479
"""
480
# TODO:
481
# * Surface -- behavior of functions not defined everywhere -- see note above
482
# * Iterative refinement
483
484
485
# color_function -- (default: "automatic") how to determine the color of curves and surfaces
486
# color_function_scaling -- (default: True) whether to scale the input to color_function
487
# exclusions -- (default: "automatic") u points or (u,v) conditions to exclude.
488
# (E.g., exclusions could be a function e = lambda u, v: False if u < v else True
489
# exclusions_style -- (default: None) what to draw at excluded points
490
# max_recursion -- (default: "automatic") maximum number of recursive subdivisions,
491
# when ...
492
# mesh -- (default: "automatic") how many mesh divisions in each direction to draw
493
# mesh_functions -- (default: "automatic") how to determine the placement of mesh divisions
494
# mesh_shading -- (default: None) how to shade regions between mesh divisions
495
# plot_range -- (default: "automatic") range of values to include
496
497
if is_Vector(f):
498
f = tuple(f)
499
500
if isinstance(f, (list,tuple)) and len(f) > 0 and isinstance(f[0], (list,tuple)):
501
return sum([parametric_plot3d(v, urange, vrange, plot_points=plot_points, **kwds) for v in f])
502
503
if not isinstance(f, (tuple, list)) or len(f) != 3:
504
raise ValueError, "f must be a list, tuple, or vector of length 3"
505
506
if vrange is None:
507
if plot_points == "automatic":
508
plot_points = 75
509
G = _parametric_plot3d_curve(f, urange, plot_points=plot_points, **kwds)
510
else:
511
if plot_points == "automatic":
512
plot_points = [40,40]
513
G = _parametric_plot3d_surface(f, urange, vrange, plot_points=plot_points, boundary_style=boundary_style, **kwds)
514
G._set_extra_kwds(kwds)
515
return G
516
517
def _parametric_plot3d_curve(f, urange, plot_points, **kwds):
518
r"""
519
Return a parametric three-dimensional space curve.
520
This function is used internally by the
521
:func:`parametric_plot3d` command.
522
523
There are two ways this function is invoked by
524
:func:`parametric_plot3d`.
525
526
- ``parametric_plot3d([f_x, f_y, f_z], (u_min,
527
u_max))``:
528
`f_x, f_y, f_z` are three functions and
529
`u_{\min}` and `u_{\max}` are real numbers
530
531
- ``parametric_plot3d([f_x, f_y, f_z], (u, u_min,
532
u_max))``:
533
`f_x, f_y, f_z` can be viewed as functions of
534
`u`
535
536
INPUT:
537
538
- ``f`` - a 3-tuple of functions or expressions, or vector of size 3
539
540
- ``urange`` - a 2-tuple (u_min, u_max) or a 3-tuple
541
(u, u_min, u_max)
542
543
- ``plot_points`` - (default: "automatic", which is 75) initial
544
number of sample points in each parameter; an integer.
545
546
EXAMPLES:
547
548
We demonstrate each of the two ways of calling this. See
549
:func:`parametric_plot3d` for many more examples.
550
551
We do the first one with a lambda function, which creates a
552
callable Python function that sends `u` to `u/10`::
553
554
sage: parametric_plot3d( (sin, cos, lambda u: u/10), (0, 20)) # indirect doctest
555
556
Now we do the same thing with symbolic expressions::
557
558
sage: u = var('u')
559
sage: parametric_plot3d( (sin(u), cos(u), u/10), (u, 0, 20))
560
"""
561
from sage.plot.misc import setup_for_eval_on_grid
562
g, ranges = setup_for_eval_on_grid(f, [urange], plot_points)
563
f_x,f_y,f_z = g
564
w = [(f_x(u), f_y(u), f_z(u)) for u in xsrange(*ranges[0], include_endpoint=True)]
565
return line3d(w, **kwds)
566
567
def _parametric_plot3d_surface(f, urange, vrange, plot_points, boundary_style, **kwds):
568
r"""
569
Return a parametric three-dimensional space surface.
570
This function is used internally by the
571
:func:`parametric_plot3d` command.
572
573
There are two ways this function is invoked by
574
:func:`parametric_plot3d`.
575
576
- ``parametric_plot3d([f_x, f_y, f_z], (u_min, u_max),
577
(v_min, v_max))``:
578
`f_x, f_y, f_z` are each functions of two variables
579
580
- ``parametric_plot3d([f_x, f_y, f_z], (u, u_min,
581
u_max), (v, v_min, v_max))``:
582
`f_x, f_y, f_z` can be viewed as functions of
583
`u` and `v`
584
585
INPUT:
586
587
- ``f`` - a 3-tuple of functions or expressions, or vector of size 3
588
589
- ``urange`` - a 2-tuple (u_min, u_max) or a 3-tuple
590
(u, u_min, u_max)
591
592
- ``vrange`` - a 2-tuple (v_min, v_max) or a 3-tuple
593
(v, v_min, v_max)
594
595
- ``plot_points`` - (default: "automatic", which is [40,40]
596
for surfaces) initial number of sample points in each parameter;
597
a pair of integers.
598
599
- ``boundary_style`` - (default: None, no boundary) a dict that describes
600
how to draw the boundaries of regions by giving options that are passed
601
to the line3d command.
602
603
EXAMPLES:
604
605
We demonstrate each of the two ways of calling this. See
606
:func:`parametric_plot3d` for many more examples.
607
608
We do the first one with lambda functions::
609
610
sage: f = (lambda u,v: cos(u), lambda u,v: sin(u)+cos(v), lambda u,v: sin(v))
611
sage: parametric_plot3d(f, (0, 2*pi), (-pi, pi)) # indirect doctest
612
613
Now we do the same thing with symbolic expressions::
614
615
sage: u, v = var('u,v')
616
sage: parametric_plot3d((cos(u), sin(u) + cos(v), sin(v)), (u, 0, 2*pi), (v, -pi, pi), mesh=True)
617
"""
618
from sage.plot.misc import setup_for_eval_on_grid
619
g, ranges = setup_for_eval_on_grid(f, [urange,vrange], plot_points)
620
urange = srange(*ranges[0], include_endpoint=True)
621
vrange = srange(*ranges[1], include_endpoint=True)
622
G = ParametricSurface(g, (urange, vrange), **kwds)
623
624
if boundary_style is not None:
625
for u in (urange[0], urange[-1]):
626
G += line3d([(g[0](u,v), g[1](u,v), g[2](u,v)) for v in vrange], **boundary_style)
627
for v in (vrange[0], vrange[-1]):
628
G += line3d([(g[0](u,v), g[1](u,v), g[2](u,v)) for u in urange], **boundary_style)
629
return G
630
631