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.

Files changed (81) hide show
  1. passagemath_plot-10.6.31rc3.dist-info/METADATA +172 -0
  2. passagemath_plot-10.6.31rc3.dist-info/RECORD +81 -0
  3. passagemath_plot-10.6.31rc3.dist-info/WHEEL +6 -0
  4. passagemath_plot-10.6.31rc3.dist-info/top_level.txt +2 -0
  5. passagemath_plot.libs/libgfortran-e1b7dfc8.so.5.0.0 +0 -0
  6. passagemath_plot.libs/libgsl-e3525837.so.28.0.0 +0 -0
  7. passagemath_plot.libs/libopenblasp-r0-4c5b64b1.3.29.so +0 -0
  8. sage/all__sagemath_plot.py +15 -0
  9. sage/ext_data/threejs/animation.css +195 -0
  10. sage/ext_data/threejs/animation.html +85 -0
  11. sage/ext_data/threejs/animation.js +273 -0
  12. sage/ext_data/threejs/fat_lines.js +48 -0
  13. sage/ext_data/threejs/threejs-version.txt +1 -0
  14. sage/ext_data/threejs/threejs_template.html +597 -0
  15. sage/interfaces/all__sagemath_plot.py +1 -0
  16. sage/interfaces/gnuplot.py +196 -0
  17. sage/interfaces/jmoldata.py +208 -0
  18. sage/interfaces/povray.py +56 -0
  19. sage/plot/all.py +42 -0
  20. sage/plot/animate.py +1796 -0
  21. sage/plot/arc.py +504 -0
  22. sage/plot/arrow.py +671 -0
  23. sage/plot/bar_chart.py +205 -0
  24. sage/plot/bezier_path.py +400 -0
  25. sage/plot/circle.py +435 -0
  26. sage/plot/colors.py +1606 -0
  27. sage/plot/complex_plot.cpython-314-aarch64-linux-gnu.so +0 -0
  28. sage/plot/complex_plot.pyx +1446 -0
  29. sage/plot/contour_plot.py +1792 -0
  30. sage/plot/density_plot.py +318 -0
  31. sage/plot/disk.py +373 -0
  32. sage/plot/ellipse.py +375 -0
  33. sage/plot/graphics.py +3580 -0
  34. sage/plot/histogram.py +354 -0
  35. sage/plot/hyperbolic_arc.py +404 -0
  36. sage/plot/hyperbolic_polygon.py +416 -0
  37. sage/plot/hyperbolic_regular_polygon.py +296 -0
  38. sage/plot/line.py +626 -0
  39. sage/plot/matrix_plot.py +629 -0
  40. sage/plot/misc.py +509 -0
  41. sage/plot/multigraphics.py +1294 -0
  42. sage/plot/plot.py +4183 -0
  43. sage/plot/plot3d/all.py +23 -0
  44. sage/plot/plot3d/base.cpython-314-aarch64-linux-gnu.so +0 -0
  45. sage/plot/plot3d/base.pxd +12 -0
  46. sage/plot/plot3d/base.pyx +3378 -0
  47. sage/plot/plot3d/implicit_plot3d.py +659 -0
  48. sage/plot/plot3d/implicit_surface.cpython-314-aarch64-linux-gnu.so +0 -0
  49. sage/plot/plot3d/implicit_surface.pyx +1453 -0
  50. sage/plot/plot3d/index_face_set.cpython-314-aarch64-linux-gnu.so +0 -0
  51. sage/plot/plot3d/index_face_set.pxd +32 -0
  52. sage/plot/plot3d/index_face_set.pyx +1873 -0
  53. sage/plot/plot3d/introduction.py +131 -0
  54. sage/plot/plot3d/list_plot3d.py +649 -0
  55. sage/plot/plot3d/parametric_plot3d.py +1130 -0
  56. sage/plot/plot3d/parametric_surface.cpython-314-aarch64-linux-gnu.so +0 -0
  57. sage/plot/plot3d/parametric_surface.pxd +12 -0
  58. sage/plot/plot3d/parametric_surface.pyx +893 -0
  59. sage/plot/plot3d/platonic.py +601 -0
  60. sage/plot/plot3d/plot3d.py +1442 -0
  61. sage/plot/plot3d/plot_field3d.py +162 -0
  62. sage/plot/plot3d/point_c.pxi +148 -0
  63. sage/plot/plot3d/revolution_plot3d.py +309 -0
  64. sage/plot/plot3d/shapes.cpython-314-aarch64-linux-gnu.so +0 -0
  65. sage/plot/plot3d/shapes.pxd +22 -0
  66. sage/plot/plot3d/shapes.pyx +1382 -0
  67. sage/plot/plot3d/shapes2.py +1512 -0
  68. sage/plot/plot3d/tachyon.py +1779 -0
  69. sage/plot/plot3d/texture.py +453 -0
  70. sage/plot/plot3d/transform.cpython-314-aarch64-linux-gnu.so +0 -0
  71. sage/plot/plot3d/transform.pxd +21 -0
  72. sage/plot/plot3d/transform.pyx +268 -0
  73. sage/plot/plot3d/tri_plot.py +589 -0
  74. sage/plot/plot_field.py +362 -0
  75. sage/plot/point.py +624 -0
  76. sage/plot/polygon.py +562 -0
  77. sage/plot/primitive.py +249 -0
  78. sage/plot/scatter_plot.py +199 -0
  79. sage/plot/step.py +85 -0
  80. sage/plot/streamline_plot.py +328 -0
  81. 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)])