Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/plot/plot3d/list_plot3d.py
4036 views
1
"""
2
List Plots
3
"""
4
5
from sage.matrix.all import is_Matrix, 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
corr_matrix=numpy.corrcoef(x,y)
367
368
if corr_matrix[0,1] > .9 or corr_matrix[0,1] < -.9:
369
# If the x,y coordinates lie in a one-dimensional subspace
370
# The scipy delauney code segfaults
371
# We compute the correlation of the x and y coordinates
372
# and add small random noise to avoid the problem
373
# if it looks like there is an issue
374
375
ep=float(.000001)
376
x=[float(p[0])+random()*ep for p in v]
377
y=[float(p[1])+random()*ep for p in v]
378
379
380
#If the list of data points has two points with the exact same x,y coordinate and different z coordinates
381
#then scipy sometimes segfaults. The following block checks for this. alternatively the code in the if block
382
#above which adds random error could be applied to perturb the points, but probably an exception should be raised
383
#The code also removes duplicate points which scipy can't handle.
384
385
drop_list=[]
386
387
for i in range(len(x)):
388
for j in range(i+1,len(x)):
389
if x[i]==x[j] and y[i]==y[j]:
390
if z[i]!=z[j]:
391
raise ValueError, "Two points with same x,y coordinates and different z coordinates were given. Interpolation cannot handle this."
392
elif z[i]==z[j]:
393
drop_list.append(j)
394
395
x=[x[i] for i in range(len(x)) if i not in drop_list]
396
y=[y[i] for i in range(len(x)) if i not in drop_list]
397
z=[z[i] for i in range(len(x)) if i not in drop_list]
398
399
xmin=float(min(x))
400
xmax=float(max(x))
401
ymin=float(min(y))
402
ymax=float(max(y))
403
404
num_points= kwds['num_points'] if kwds.has_key('num_points') else int(4*numpy.sqrt(len(x)))
405
#arbitrary choice - assuming more or less a nxn grid of points
406
# x should have n^2 entries. We sample 4 times that many points.
407
408
409
410
if interpolation_type == 'linear':
411
412
T= delaunay.Triangulation(x,y)
413
f=T.linear_interpolator(z)
414
f.default_value=0.0
415
j=numpy.complex(0,1)
416
vals=f[ymin:ymax:j*num_points,xmin:xmax:j*num_points]
417
from parametric_surface import ParametricSurface
418
419
def g(x,y):
420
i=round( (x-xmin)/(xmax-xmin)*(num_points-1) )
421
j=round( (y-ymin)/(ymax-ymin)*(num_points-1) )
422
z=vals[int(j),int(i)]
423
return (x,y,z)
424
425
426
G = ParametricSurface(g, (list(numpy.r_[xmin:xmax:num_points*j]), list(numpy.r_[ymin:ymax:num_points*j])), texture=texture, **kwds)
427
G._set_extra_kwds(kwds)
428
return G
429
430
431
if interpolation_type == 'nn' or interpolation_type =='default':
432
433
T=delaunay.Triangulation(x,y)
434
f=T.nn_interpolator(z)
435
f.default_value=0.0
436
j=numpy.complex(0,1)
437
vals=f[ymin:ymax:j*num_points,xmin:xmax:j*num_points]
438
from parametric_surface import ParametricSurface
439
def g(x,y):
440
i=round( (x-xmin)/(xmax-xmin)*(num_points-1) )
441
j=round( (y-ymin)/(ymax-ymin)*(num_points-1) )
442
z=vals[int(j),int(i)]
443
return (x,y,z)
444
445
G = ParametricSurface(g, (list(numpy.r_[xmin:xmax:num_points*j]), list(numpy.r_[ymin:ymax:num_points*j])), texture=texture, **kwds)
446
G._set_extra_kwds(kwds)
447
return G
448
449
if interpolation_type =='spline':
450
from plot3d import plot3d
451
kx=kwds['kx'] if kwds.has_key('kx') else 3
452
ky=kwds['ky'] if kwds.has_key('ky') else 3
453
if kwds.has_key('degree'):
454
kx=kwds['degree']
455
ky=kwds['degree']
456
457
s=kwds['smoothing'] if kwds.has_key('smoothing') else len(x)-numpy.sqrt(2*len(x))
458
s=interpolate.bisplrep(x,y,z,[int(1)]*len(x),xmin,xmax,ymin,ymax,kx=kx,ky=ky,s=s)
459
f=lambda x,y: interpolate.bisplev(x,y,s)
460
return plot3d(f,(xmin,xmax),(ymin,ymax),texture=texture,plot_points=[num_points,num_points],**kwds)
461
462