Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/plot/plot3d/list_plot3d.py
8815 views
1
"""
2
List Plots
3
"""
4
from sage.matrix.matrix import is_Matrix
5
from sage.matrix.all import matrix
6
from sage.rings.all import RDF
7
8
def list_plot3d(v, interpolation_type='default', texture="automatic", point_list=None,**kwds):
9
r"""
10
A 3-dimensional plot of a surface defined by the list `v`
11
of points in 3-dimensional space.
12
13
INPUT:
14
15
16
- ``v`` - something that defines a set of points in 3
17
space, for example:
18
19
- a matrix
20
21
- a list of 3-tuples
22
23
- a list of lists (all of the same length) - this is treated the same as
24
a matrix.
25
26
- ``texture`` - (default: "automatic", a solid light blue)
27
28
OPTIONAL KEYWORDS:
29
30
- ``interpolation_type`` - 'linear', 'nn' (nearest neighbor), 'spline'
31
32
'linear' will perform linear interpolation
33
34
The option 'nn' will interpolate by averaging the value of the
35
nearest neighbors, this produces an interpolating function that is
36
smoother than a linear interpolation, it has one derivative
37
everywhere except at the sample points.
38
39
The option 'spline' interpolates using a bivariate B-spline.
40
41
When v is a matrix the default is to use linear interpolation, when
42
v is a list of points the default is nearest neighbor.
43
44
- ``degree`` - an integer between 1 and 5, controls the degree of spline
45
used for spline interpolation. For data that is highly oscillatory
46
use higher values
47
48
- ``point_list`` - If point_list=True is passed, then if the array
49
is a list of lists of length three, it will be treated as an
50
array of points rather than a 3xn array.
51
52
- ``num_points`` - Number of points to sample interpolating
53
function in each direction, when ``interpolation_type`` is not
54
``default``. By default for an `n\times n` array this is `n`.
55
56
- ``**kwds`` - all other arguments are passed to the surface function
57
58
OUTPUT: a 3d plot
59
60
EXAMPLES:
61
62
We plot a matrix that illustrates summation modulo `n`.
63
64
::
65
66
sage: n = 5; list_plot3d(matrix(RDF,n,[(i+j)%n for i in [1..n] for j in [1..n]]))
67
68
We plot a matrix of values of sin.
69
70
::
71
72
sage: pi = float(pi)
73
sage: m = matrix(RDF, 6, [sin(i^2 + j^2) for i in [0,pi/5,..,pi] for j in [0,pi/5,..,pi]])
74
sage: list_plot3d(m, texture='yellow', frame_aspect_ratio=[1,1,1/3])
75
76
Though it doesn't change the shape of the graph, increasing
77
num_points can increase the clarity of the graph.
78
79
::
80
81
sage: list_plot3d(m, texture='yellow', frame_aspect_ratio=[1,1,1/3],num_points=40)
82
83
We can change the interpolation type.
84
85
::
86
87
sage: list_plot3d(m, texture='yellow', interpolation_type='nn',frame_aspect_ratio=[1,1,1/3])
88
89
We can make this look better by increasing the number of samples.
90
91
::
92
93
sage: list_plot3d(m, texture='yellow', interpolation_type='nn',frame_aspect_ratio=[1,1,1/3],num_points=40)
94
95
Let's try a spline.
96
97
::
98
99
sage: list_plot3d(m, texture='yellow', interpolation_type='spline',frame_aspect_ratio=[1,1,1/3])
100
101
That spline doesn't capture the oscillation very well; let's try a
102
higher degree spline.
103
104
::
105
106
sage: list_plot3d(m, texture='yellow', interpolation_type='spline', degree=5, frame_aspect_ratio=[1,1,1/3])
107
108
We plot a list of lists::
109
110
sage: show(list_plot3d([[1, 1, 1, 1], [1, 2, 1, 2], [1, 1, 3, 1], [1, 2, 1, 4]]))
111
112
We plot a list of points. As a first example we can extract the
113
(x,y,z) coordinates from the above example and make a list plot
114
out of it. By default we do linear interpolation.
115
116
::
117
118
sage: l=[]
119
sage: for i in range(6):
120
... for j in range(6):
121
... l.append((float(i*pi/5),float(j*pi/5),m[i,j]))
122
sage: list_plot3d(l,texture='yellow')
123
124
Note that the points do not have to be regularly sampled. For example::
125
126
sage: l=[]
127
sage: for i in range(-5,5):
128
... for j in range(-5,5):
129
... l.append((normalvariate(0,1),normalvariate(0,1),normalvariate(0,1)))
130
sage: list_plot3d(l,interpolation_type='nn',texture='yellow',num_points=100)
131
132
TESTS:
133
134
We plot 0, 1, and 2 points::
135
136
sage: list_plot3d([])
137
138
::
139
140
sage: list_plot3d([(2,3,4)])
141
142
::
143
144
sage: list_plot3d([(0,0,1), (2,3,4)])
145
146
However, if two points are given with the same x,y coordinates but
147
different z coordinates, an exception will be raised::
148
149
sage: pts =[(-4/5, -2/5, -2/5), (-4/5, -2/5, 2/5), (-4/5, 2/5, -2/5), (-4/5, 2/5, 2/5), (-2/5, -4/5, -2/5), (-2/5, -4/5, 2/5), (-2/5, -2/5, -4/5), (-2/5, -2/5, 4/5), (-2/5, 2/5, -4/5), (-2/5, 2/5, 4/5), (-2/5, 4/5, -2/5), (-2/5, 4/5, 2/5), (2/5, -4/5, -2/5), (2/5, -4/5, 2/5), (2/5, -2/5, -4/5), (2/5, -2/5, 4/5), (2/5, 2/5, -4/5), (2/5, 2/5, 4/5), (2/5, 4/5, -2/5), (2/5, 4/5, 2/5), (4/5, -2/5, -2/5), (4/5, -2/5, 2/5), (4/5, 2/5, -2/5), (4/5, 2/5, 2/5)]
150
sage: show(list_plot3d(pts, interpolation_type='nn'))
151
Traceback (most recent call last):
152
...
153
ValueError: Two points with same x,y coordinates and different z coordinates were given. Interpolation cannot handle this.
154
155
Additionally we need at least 3 points to do the interpolation::
156
157
sage: mat = matrix(RDF, 1, 2, [3.2, 1.550])
158
sage: show(list_plot3d(mat,interpolation_type='nn'))
159
Traceback (most recent call last):
160
...
161
ValueError: We need at least 3 points to perform the interpolation
162
"""
163
import numpy
164
if texture == "automatic":
165
texture = "lightblue"
166
if is_Matrix(v):
167
if interpolation_type=='default' or interpolation_type=='linear' and not kwds.has_key('num_points'):
168
return list_plot3d_matrix(v, texture=texture, **kwds)
169
else:
170
l=[]
171
for i in xrange(v.nrows()):
172
for j in xrange(v.ncols()):
173
l.append((i,j,v[i,j]))
174
return list_plot3d_tuples(l,interpolation_type,texture,**kwds)
175
176
if type(v)==numpy.ndarray:
177
return list_plot3d(matrix(v),interpolation_type,texture,**kwds)
178
179
if isinstance(v, list):
180
if len(v) == 0:
181
# return empty 3d graphic
182
from base import Graphics3d
183
return Graphics3d()
184
elif len(v) == 1:
185
# return a point
186
from shapes2 import point3d
187
return point3d(v[0], **kwds)
188
elif len(v) == 2:
189
# return a line
190
from shapes2 import line3d
191
return line3d(v, **kwds)
192
elif isinstance(v[0],tuple) or point_list==True and len(v[0]) == 3:
193
return list_plot3d_tuples(v,interpolation_type,texture=texture, **kwds)
194
else:
195
return list_plot3d_array_of_arrays(v, interpolation_type,texture, **kwds)
196
raise TypeError, "v must be a matrix or list"
197
198
def list_plot3d_matrix(m, texture, **kwds):
199
"""
200
A 3-dimensional plot of a surface defined by a matrix ``M``
201
defining points in 3-dimensional space. See :func:`list_plot3d`
202
for full details.
203
204
INPUT:
205
206
- ``M`` - a matrix
207
- ``texture`` - (default: "automatic", a solid light blue)
208
209
OPTIONAL KEYWORDS:
210
211
- ``**kwds`` - all other arguments are passed to the
212
surface function
213
214
OUTPUT: a 3d plot
215
216
EXAMPLES:
217
218
We plot a matrix that illustrates summation modulo `n`::
219
220
sage: n = 5; list_plot3d(matrix(RDF,n,[(i+j)%n for i in [1..n] for j in [1..n]])) # indirect doctest
221
222
The interpolation type for matrices is 'linear'; for other types
223
use other :func:`list_plot3d` input types.
224
225
We plot a matrix of values of `sin`::
226
227
sage: pi = float(pi)
228
sage: m = matrix(RDF, 6, [sin(i^2 + j^2) for i in [0,pi/5,..,pi] for j in [0,pi/5,..,pi]])
229
sage: list_plot3d(m, texture='yellow', frame_aspect_ratio=[1,1,1/3]) # indirect doctest
230
sage: list_plot3d(m, texture='yellow', interpolation_type='linear') # indirect doctest
231
"""
232
from parametric_surface import ParametricSurface
233
f = lambda i,j: (i,j,float(m[int(i),int(j)]))
234
G = ParametricSurface(f, (range(m.nrows()), range(m.ncols())), texture=texture, **kwds)
235
G._set_extra_kwds(kwds)
236
return G
237
238
def list_plot3d_array_of_arrays(v, interpolation_type, texture, **kwds):
239
"""
240
A 3-dimensional plot of a surface defined by a list of lists ``v``
241
defining points in 3-dimensional space. This is done by making the
242
list of lists into a matrix and passing back to :func:`list_plot3d`.
243
See :func:`list_plot3d` for full details.
244
245
INPUT:
246
247
- ``v`` - a list of lists, all the same length
248
- ``interpolation_type`` - (default: 'linear')
249
- ``texture`` - (default: "automatic", a solid light blue)
250
251
OPTIONAL KEYWORDS:
252
253
- ``**kwds`` - all other arguments are passed to the surface function
254
255
OUTPUT: a 3d plot
256
257
EXAMPLES:
258
259
The resulting matrix does not have to be square::
260
261
sage: show(list_plot3d([[1, 1, 1, 1], [1, 2, 1, 2], [1, 1, 3, 1]])) # indirect doctest
262
263
The normal route is for the list of lists to be turned into a matrix
264
and use :func:`list_plot3d_matrix`::
265
266
sage: show(list_plot3d([[1, 1, 1, 1], [1, 2, 1, 2], [1, 1, 3, 1], [1, 2, 1, 4]]))
267
268
With certain extra keywords (see :func:`list_plot3d_matrix`), this function
269
will end up using :func:`list_plot3d_tuples`::
270
271
sage: show(list_plot3d([[1, 1, 1, 1], [1, 2, 1, 2], [1, 1, 3, 1], [1, 2, 1, 4]],interpolation_type='spline'))
272
"""
273
m = matrix(RDF, len(v), len(v[0]), v)
274
G = list_plot3d(m,interpolation_type,texture, **kwds)
275
G._set_extra_kwds(kwds)
276
return G
277
278
def list_plot3d_tuples(v,interpolation_type, texture, **kwds):
279
r"""
280
A 3-dimensional plot of a surface defined by the list `v`
281
of points in 3-dimensional space.
282
283
INPUT:
284
285
- ``v`` - something that defines a set of points in 3
286
space, for example:
287
288
- a matrix
289
290
This will be if using an interpolation type other than 'linear', or if using
291
``num_points`` with 'linear'; otherwise see :func:`list_plot3d_matrix`.
292
293
- a list of 3-tuples
294
295
- a list of lists (all of the same length, under same conditions as a matrix)
296
297
- ``texture`` - (default: "automatic", a solid light blue)
298
299
OPTIONAL KEYWORDS:
300
301
- ``interpolation_type`` - 'linear', 'nn' (nearest neighbor), 'spline'
302
303
'linear' will perform linear interpolation
304
305
The option 'nn' will interpolate by averaging the value of the
306
nearest neighbors, this produces an interpolating function that is
307
smoother than a linear interpolation, it has one derivative
308
everywhere except at the sample points.
309
310
The option 'spline' interpolates using a bivariate B-spline.
311
312
When v is a matrix the default is to use linear interpolation, when
313
v is a list of points the default is nearest neighbor.
314
315
- ``degree`` - an integer between 1 and 5, controls the degree of spline
316
used for spline interpolation. For data that is highly oscillatory
317
use higher values
318
319
- ``point_list`` - If point_list=True is passed, then if the array
320
is a list of lists of length three, it will be treated as an
321
array of points rather than a `3\times n` array.
322
323
- ``num_points`` - Number of points to sample interpolating
324
function in each direction. By default for an `n\times n`
325
array this is `n`.
326
327
- ``**kwds`` - all other arguments are passed to the
328
surface function
329
330
OUTPUT: a 3d plot
331
332
EXAMPLES:
333
334
All of these use this function; see :func:`list_plot3d` for other list plots::
335
336
sage: pi = float(pi)
337
sage: m = matrix(RDF, 6, [sin(i^2 + j^2) for i in [0,pi/5,..,pi] for j in [0,pi/5,..,pi]])
338
sage: list_plot3d(m, texture='yellow', interpolation_type='linear', num_points=5) # indirect doctest
339
340
::
341
342
sage: list_plot3d(m, texture='yellow', interpolation_type='spline',frame_aspect_ratio=[1,1,1/3])
343
344
::
345
346
sage: show(list_plot3d([[1, 1, 1], [1, 2, 1], [0, 1, 3], [1, 0, 4]],point_list=True))
347
348
::
349
350
sage: list_plot3d([(1,2,3),(0,1,3),(2,1,4),(1,0,-2)], texture='yellow', num_points=50)
351
"""
352
from matplotlib import delaunay
353
import numpy
354
import scipy
355
from random import random
356
from scipy import interpolate
357
from plot3d import plot3d
358
359
if len(v)<3:
360
raise ValueError, "We need at least 3 points to perform the interpolation"
361
362
x=[float(p[0]) for p in v]
363
y=[float(p[1]) for p in v]
364
z=[float(p[2]) for p in v]
365
366
# If the (x,y)-coordinates lie in a one-dimensional subspace, the
367
# matplotlib Delaunay code segfaults. Therefore, we compute the
368
# correlation of the x- and y-coordinates and add small random
369
# noise to avoid the problem if needed.
370
corr_matrix = numpy.corrcoef(x,y)
371
if corr_matrix[0,1] > 0.9 or corr_matrix[0,1] < -0.9:
372
ep = float(.000001)
373
x = [float(p[0]) + random()*ep for p in v]
374
y = [float(p[1]) + random()*ep for p in v]
375
376
377
# If the list of data points has two points with the exact same
378
# (x,y)-coordinate but different z-coordinates, then we sometimes
379
# get segfaults. The following block checks for this and raises
380
# an exception if this is the case.
381
# We also remove duplicate points (which matplotlib can't handle).
382
# Alternatively, the code in the if block above which adds random
383
# error could be applied to perturb the points.
384
drop_list=[]
385
for i in range(len(x)):
386
for j in range(i+1,len(x)):
387
if x[i]==x[j] and y[i]==y[j]:
388
if z[i]!=z[j]:
389
raise ValueError, "Two points with same x,y coordinates and different z coordinates were given. Interpolation cannot handle this."
390
elif z[i]==z[j]:
391
drop_list.append(j)
392
393
x=[x[i] for i in range(len(x)) if i not in drop_list]
394
y=[y[i] for i in range(len(x)) if i not in drop_list]
395
z=[z[i] for i in range(len(x)) if i not in drop_list]
396
397
xmin=float(min(x))
398
xmax=float(max(x))
399
ymin=float(min(y))
400
ymax=float(max(y))
401
402
num_points= kwds['num_points'] if kwds.has_key('num_points') else int(4*numpy.sqrt(len(x)))
403
#arbitrary choice - assuming more or less a nxn grid of points
404
# x should have n^2 entries. We sample 4 times that many points.
405
406
407
408
if interpolation_type == 'linear':
409
410
T= delaunay.Triangulation(x,y)
411
f=T.linear_interpolator(z)
412
f.default_value=0.0
413
j=numpy.complex(0,1)
414
vals=f[ymin:ymax:j*num_points,xmin:xmax:j*num_points]
415
from parametric_surface import ParametricSurface
416
417
def g(x,y):
418
i=round( (x-xmin)/(xmax-xmin)*(num_points-1) )
419
j=round( (y-ymin)/(ymax-ymin)*(num_points-1) )
420
z=vals[int(j),int(i)]
421
return (x,y,z)
422
423
424
G = ParametricSurface(g, (list(numpy.r_[xmin:xmax:num_points*j]), list(numpy.r_[ymin:ymax:num_points*j])), texture=texture, **kwds)
425
G._set_extra_kwds(kwds)
426
return G
427
428
429
if interpolation_type == 'nn' or interpolation_type =='default':
430
431
T=delaunay.Triangulation(x,y)
432
f=T.nn_interpolator(z)
433
f.default_value=0.0
434
j=numpy.complex(0,1)
435
vals=f[ymin:ymax:j*num_points,xmin:xmax:j*num_points]
436
from parametric_surface import ParametricSurface
437
def g(x,y):
438
i=round( (x-xmin)/(xmax-xmin)*(num_points-1) )
439
j=round( (y-ymin)/(ymax-ymin)*(num_points-1) )
440
z=vals[int(j),int(i)]
441
return (x,y,z)
442
443
G = ParametricSurface(g, (list(numpy.r_[xmin:xmax:num_points*j]), list(numpy.r_[ymin:ymax:num_points*j])), texture=texture, **kwds)
444
G._set_extra_kwds(kwds)
445
return G
446
447
if interpolation_type =='spline':
448
from plot3d import plot3d
449
kx=kwds['kx'] if kwds.has_key('kx') else 3
450
ky=kwds['ky'] if kwds.has_key('ky') else 3
451
if kwds.has_key('degree'):
452
kx=kwds['degree']
453
ky=kwds['degree']
454
455
s=kwds['smoothing'] if kwds.has_key('smoothing') else len(x)-numpy.sqrt(2*len(x))
456
s=interpolate.bisplrep(x,y,z,[int(1)]*len(x),xmin,xmax,ymin,ymax,kx=kx,ky=ky,s=s)
457
f=lambda x,y: interpolate.bisplev(x,y,s)
458
return plot3d(f,(xmin,xmax),(ymin,ymax),texture=texture,plot_points=[num_points,num_points],**kwds)
459
460