Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

367

368

369

370

371

372

373

374

375

376

377

378

379

380

381

382

383

384

385

386

387

388

389

390

391

392

393

394

395

396

397

398

399

400

401

402

403

404

405

406

407

408

409

410

411

412

413

414

415

416

417

418

419

420

421

422

423

424

425

426

427

428

429

430

431

432

433

434

435

436

437

438

439

440

441

442

443

444

445

446

447

448

449

450

451

452

453

454

455

456

457

458

459

460

461

462

463

464

465

466

467

468

469

470

471

472

473

474

475

476

477

478

479

480

481

482

483

484

485

486

487

488

489

490

""" 

List Plots 

""" 

from __future__ import absolute_import 

from six.moves import range 

 

from sage.structure.element import is_Matrix 

from sage.matrix.all import matrix 

from sage.rings.all import RDF 

 

def list_plot3d(v, interpolation_type='default', texture="automatic", point_list=None, **kwds): 

r""" 

A 3-dimensional plot of a surface defined by the list `v` 

of points in 3-dimensional space. 

 

INPUT: 

 

- ``v`` - something that defines a set of points in 3 

space, for example: 

 

- a matrix 

 

- a list of 3-tuples 

 

- a list of lists (all of the same length) - this is treated the same as 

a matrix. 

 

- ``texture`` - (default: "automatic", a solid light blue) 

 

OPTIONAL KEYWORDS: 

 

- ``interpolation_type`` - 'linear', 'clough' (CloughTocher2D), 'spline' 

 

'linear' will perform linear interpolation 

 

The option 'clough' will interpolate by using a piecewise cubic interpolating 

Bezier polynomial on each triangle, using a Clough-Tocher scheme. 

The interpolant is guaranteed to be continuously differentiable. 

The gradients of the interpolant are chosen so that the curvature of the 

interpolating surface is approximatively minimized. 

 

The option 'spline' interpolates using a bivariate B-spline. 

 

When v is a matrix the default is to use linear interpolation, when 

v is a list of points the default is 'clough'. 

 

- ``degree`` - an integer between 1 and 5, controls the degree of spline 

used for spline interpolation. For data that is highly oscillatory 

use higher values 

 

- ``point_list`` - If point_list=True is passed, then if the array 

is a list of lists of length three, it will be treated as an 

array of points rather than a 3xn array. 

 

- ``num_points`` - Number of points to sample interpolating 

function in each direction, when ``interpolation_type`` is not 

``default``. By default for an `n\times n` array this is `n`. 

 

- ``**kwds`` - all other arguments are passed to the surface function 

 

OUTPUT: a 3d plot 

 

EXAMPLES: 

 

We plot a matrix that illustrates summation modulo `n`. 

 

:: 

 

sage: n = 5; list_plot3d(matrix(RDF, n, [(i+j)%n for i in [1..n] for j in [1..n]])) 

Graphics3d Object 

 

We plot a matrix of values of sin. 

 

:: 

 

sage: pi = float(pi) 

sage: m = matrix(RDF, 6, [sin(i^2 + j^2) for i in [0,pi/5,..,pi] for j in [0,pi/5,..,pi]]) 

sage: list_plot3d(m, texture='yellow', frame_aspect_ratio=[1, 1, 1/3]) 

Graphics3d Object 

 

Though it doesn't change the shape of the graph, increasing 

num_points can increase the clarity of the graph. 

 

:: 

 

sage: list_plot3d(m, texture='yellow', frame_aspect_ratio=[1, 1, 1/3], num_points=40) 

Graphics3d Object 

 

We can change the interpolation type. 

 

:: 

 

sage: import warnings 

sage: warnings.simplefilter('ignore', UserWarning) 

sage: list_plot3d(m, texture='yellow', interpolation_type='clough', frame_aspect_ratio=[1, 1, 1/3]) 

Graphics3d Object 

 

We can make this look better by increasing the number of samples. 

 

:: 

 

sage: list_plot3d(m, texture='yellow', interpolation_type='clough', frame_aspect_ratio=[1, 1, 1/3], num_points=40) 

Graphics3d Object 

 

Let's try a spline. 

 

:: 

 

sage: list_plot3d(m, texture='yellow', interpolation_type='spline', frame_aspect_ratio=[1, 1, 1/3]) 

Graphics3d Object 

 

That spline doesn't capture the oscillation very well; let's try a 

higher degree spline. 

 

:: 

 

sage: list_plot3d(m, texture='yellow', interpolation_type='spline', degree=5, frame_aspect_ratio=[1, 1, 1/3]) 

Graphics3d Object 

 

We plot a list of lists:: 

 

sage: show(list_plot3d([[1, 1, 1, 1], [1, 2, 1, 2], [1, 1, 3, 1], [1, 2, 1, 4]])) 

 

We plot a list of points. As a first example we can extract the 

(x,y,z) coordinates from the above example and make a list plot 

out of it. By default we do linear interpolation. 

 

:: 

 

sage: l = [] 

sage: for i in range(6): 

....: for j in range(6): 

....: l.append((float(i*pi/5), float(j*pi/5), m[i, j])) 

sage: list_plot3d(l, texture='yellow') 

Graphics3d Object 

 

Note that the points do not have to be regularly sampled. For example:: 

 

sage: l = [] 

sage: for i in range(-5, 5): 

....: for j in range(-5, 5): 

....: l.append((normalvariate(0, 1), normalvariate(0, 1), normalvariate(0, 1))) 

sage: L = list_plot3d(l, interpolation_type='clough', texture='yellow', num_points=100) 

sage: L 

Graphics3d Object 

 

Check that no NaNs are produced (see :trac:`13135`):: 

 

sage: any(math.isnan(c) for v in L.vertices() for c in v) 

False 

 

TESTS: 

 

We plot 0, 1, and 2 points:: 

 

sage: list_plot3d([]) 

Graphics3d Object 

 

:: 

 

sage: list_plot3d([(2, 3, 4)]) 

Graphics3d Object 

 

:: 

 

sage: list_plot3d([(0, 0, 1), (2, 3, 4)]) 

Graphics3d Object 

 

However, if two points are given with the same x,y coordinates but 

different z coordinates, an exception will be raised:: 

 

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)] 

sage: show(list_plot3d(pts, interpolation_type='clough')) 

Traceback (most recent call last): 

... 

ValueError: Two points with same x,y coordinates and different z coordinates were given. Interpolation cannot handle this. 

 

Additionally we need at least 3 points to do the interpolation:: 

 

sage: mat = matrix(RDF, 1, 2, [3.2, 1.550]) 

sage: show(list_plot3d(mat, interpolation_type='clough')) 

Traceback (most recent call last): 

... 

ValueError: We need at least 3 points to perform the interpolation 

""" 

import numpy 

if texture == "automatic": 

texture = "lightblue" 

if is_Matrix(v): 

if interpolation_type == 'default' or interpolation_type == 'linear' and 'num_points' not in kwds: 

return list_plot3d_matrix(v, texture=texture, **kwds) 

else: 

l = [] 

for i in range(v.nrows()): 

for j in range(v.ncols()): 

l.append((i, j, v[i, j])) 

return list_plot3d_tuples(l, interpolation_type, texture, **kwds) 

 

if isinstance(v, numpy.ndarray): 

return list_plot3d(matrix(v), interpolation_type, texture, **kwds) 

 

if isinstance(v, list): 

if len(v) == 0: 

# return empty 3d graphic 

from .base import Graphics3d 

return Graphics3d() 

elif len(v) == 1: 

# return a point 

from .shapes2 import point3d 

return point3d(v[0], **kwds) 

elif len(v) == 2: 

# return a line 

from .shapes2 import line3d 

return line3d(v, **kwds) 

elif isinstance(v[0], tuple) or point_list and len(v[0]) == 3: 

return list_plot3d_tuples(v, interpolation_type, texture=texture, **kwds) 

else: 

return list_plot3d_array_of_arrays(v, interpolation_type, texture, **kwds) 

raise TypeError("v must be a matrix or list") 

 

 

def list_plot3d_matrix(m, texture, **kwds): 

""" 

A 3-dimensional plot of a surface defined by a matrix ``M`` 

defining points in 3-dimensional space. See :func:`list_plot3d` 

for full details. 

 

INPUT: 

 

- ``M`` - a matrix 

- ``texture`` - (default: "automatic", a solid light blue) 

 

OPTIONAL KEYWORDS: 

 

- ``**kwds`` - all other arguments are passed to the 

surface function 

 

OUTPUT: a 3d plot 

 

EXAMPLES: 

 

We plot a matrix that illustrates summation modulo `n`:: 

 

sage: n = 5; list_plot3d(matrix(RDF, n, [(i+j)%n for i in [1..n] for j in [1..n]])) # indirect doctest 

Graphics3d Object 

 

The interpolation type for matrices is 'linear'; for other types 

use other :func:`list_plot3d` input types. 

 

We plot a matrix of values of `sin`:: 

 

sage: pi = float(pi) 

sage: m = matrix(RDF, 6, [sin(i^2 + j^2) for i in [0,pi/5,..,pi] for j in [0,pi/5,..,pi]]) 

sage: list_plot3d(m, texture='yellow', frame_aspect_ratio=[1, 1, 1/3]) # indirect doctest 

Graphics3d Object 

sage: list_plot3d(m, texture='yellow', interpolation_type='linear') # indirect doctest 

Graphics3d Object 

 

Here is a colored example, using a colormap and a coloring function 

which must take values in (0, 1):: 

 

sage: cm = colormaps.rainbow 

sage: n = 20 

sage: cf = lambda x, y: ((2*(x-y)/n)**2) % 1 

sage: list_plot3d(matrix(RDF, n, [cos(pi*(i+j)/n) for i in [1..n] 

....: for j in [1..n]]), color=(cf,cm)) 

Graphics3d Object 

 

.. PLOT:: 

 

cm = colormaps.rainbow 

cf = lambda x, y: ((2*(x-y)/20)**2) % 1 

expl = list_plot3d(matrix(RDF,20,20,[cos(pi*(i+j)/20) for i in range(1,21) for j in range(1,21)]),color=(cf,cm)) 

sphinx_plot(expl)  

""" 

from .parametric_surface import ParametricSurface 

f = lambda i,j: (i, j, float(m[int(i), int(j)])) 

G = ParametricSurface(f, (list(range(m.nrows())), list(range(m.ncols()))), 

texture=texture, **kwds) 

G._set_extra_kwds(kwds) 

return G 

 

 

def list_plot3d_array_of_arrays(v, interpolation_type, texture, **kwds): 

""" 

A 3-dimensional plot of a surface defined by a list of lists ``v`` 

defining points in 3-dimensional space. This is done by making the 

list of lists into a matrix and passing back to :func:`list_plot3d`. 

See :func:`list_plot3d` for full details. 

 

INPUT: 

 

- ``v`` - a list of lists, all the same length 

- ``interpolation_type`` - (default: 'linear') 

- ``texture`` - (default: "automatic", a solid light blue) 

 

OPTIONAL KEYWORDS: 

 

- ``**kwds`` - all other arguments are passed to the surface function 

 

OUTPUT: a 3d plot 

 

EXAMPLES: 

 

The resulting matrix does not have to be square:: 

 

sage: show(list_plot3d([[1, 1, 1, 1], [1, 2, 1, 2], [1, 1, 3, 1]])) # indirect doctest 

 

The normal route is for the list of lists to be turned into a matrix 

and use :func:`list_plot3d_matrix`:: 

 

sage: show(list_plot3d([[1, 1, 1, 1], [1, 2, 1, 2], [1, 1, 3, 1], [1, 2, 1, 4]])) 

 

With certain extra keywords (see :func:`list_plot3d_matrix`), this function 

will end up using :func:`list_plot3d_tuples`:: 

 

sage: show(list_plot3d([[1, 1, 1, 1], [1, 2, 1, 2], [1, 1, 3, 1], [1, 2, 1, 4]], interpolation_type='spline')) 

""" 

m = matrix(RDF, len(v), len(v[0]), v) 

G = list_plot3d(m, interpolation_type, texture, **kwds) 

G._set_extra_kwds(kwds) 

return G 

 

def list_plot3d_tuples(v, interpolation_type, texture, **kwds): 

r""" 

A 3-dimensional plot of a surface defined by the list `v` 

of points in 3-dimensional space. 

 

INPUT: 

 

- ``v`` - something that defines a set of points in 3 

space, for example: 

 

- a matrix 

 

This will be if using an interpolation type other than 'linear', or if using 

``num_points`` with 'linear'; otherwise see :func:`list_plot3d_matrix`. 

 

- a list of 3-tuples 

 

- a list of lists (all of the same length, under same conditions as a matrix) 

 

- ``texture`` - (default: "automatic", a solid light blue) 

 

OPTIONAL KEYWORDS: 

 

- ``interpolation_type`` - 'linear', 'clough' (CloughTocher2D), 'spline' 

 

'linear' will perform linear interpolation 

 

The option 'clough' will interpolate by using a piecewise cubic interpolating 

Bezier polynomial on each triangle, using a Clough-Tocher scheme. 

The interpolant is guaranteed to be continuously differentiable. 

 

The option 'spline' interpolates using a bivariate B-spline. 

 

When v is a matrix the default is to use linear interpolation, when 

v is a list of points the default is 'clough'. 

 

- ``degree`` - an integer between 1 and 5, controls the degree of spline 

used for spline interpolation. For data that is highly oscillatory 

use higher values 

 

- ``point_list`` - If point_list=True is passed, then if the array 

is a list of lists of length three, it will be treated as an 

array of points rather than a `3\times n` array. 

 

- ``num_points`` - Number of points to sample interpolating 

function in each direction. By default for an `n\times n` 

array this is `n`. 

 

- ``**kwds`` - all other arguments are passed to the 

surface function 

 

OUTPUT: a 3d plot 

 

EXAMPLES: 

 

All of these use this function; see :func:`list_plot3d` for other list plots:: 

 

sage: pi = float(pi) 

sage: m = matrix(RDF, 6, [sin(i^2 + j^2) for i in [0,pi/5,..,pi] for j in [0,pi/5,..,pi]]) 

sage: list_plot3d(m, texture='yellow', interpolation_type='linear', num_points=5) # indirect doctest 

Graphics3d Object 

 

:: 

 

sage: list_plot3d(m, texture='yellow', interpolation_type='spline', frame_aspect_ratio=[1, 1, 1/3]) 

Graphics3d Object 

 

:: 

 

sage: show(list_plot3d([[1, 1, 1], [1, 2, 1], [0, 1, 3], [1, 0, 4]], point_list=True)) 

 

:: 

 

sage: list_plot3d([(1, 2, 3), (0, 1, 3), (2, 1, 4), (1, 0, -2)], texture='yellow', num_points=50) # long time 

Graphics3d Object 

""" 

from matplotlib import tri 

import numpy 

import scipy 

from random import random 

from scipy import interpolate 

from .plot3d import plot3d 

 

if len(v)<3: 

raise ValueError("We need at least 3 points to perform the interpolation") 

 

x = [float(p[0]) for p in v] 

y = [float(p[1]) for p in v] 

z = [float(p[2]) for p in v] 

 

# If the (x,y)-coordinates lie in a one-dimensional subspace, the 

# matplotlib Delaunay code segfaults. Therefore, we compute the 

# correlation of the x- and y-coordinates and add small random 

# noise to avoid the problem if needed. 

corr_matrix = numpy.corrcoef(x, y) 

if corr_matrix[0, 1] > 0.9 or corr_matrix[0, 1] < -0.9: 

ep = float(.000001) 

x = [float(p[0]) + random()*ep for p in v] 

y = [float(p[1]) + random()*ep for p in v] 

 

 

# If the list of data points has two points with the exact same 

# (x,y)-coordinate but different z-coordinates, then we sometimes 

# get segfaults. The following block checks for this and raises 

# an exception if this is the case. 

# We also remove duplicate points (which matplotlib can't handle). 

# Alternatively, the code in the if block above which adds random 

# error could be applied to perturb the points. 

drop_list = [] 

nb_points = len(x) 

for i in range(nb_points): 

for j in range(i+1, nb_points): 

if x[i] == x[j] and y[i] == y[j]: 

if z[i] != z[j]: 

raise ValueError("Two points with same x,y coordinates and different z coordinates were given. Interpolation cannot handle this.") 

elif z[i] == z[j]: 

drop_list.append(j) 

x = [x[i] for i in range(nb_points) if i not in drop_list] 

y = [y[i] for i in range(nb_points) if i not in drop_list] 

z = [z[i] for i in range(nb_points) if i not in drop_list] 

 

xmin = float(min(x)) 

xmax = float(max(x)) 

ymin = float(min(y)) 

ymax = float(max(y)) 

 

num_points = kwds['num_points'] if 'num_points' in kwds else int(4*numpy.sqrt(len(x))) 

#arbitrary choice - assuming more or less a nxn grid of points 

# x should have n^2 entries. We sample 4 times that many points. 

 

if interpolation_type == 'linear': 

T = tri.Triangulation(x, y) 

f = tri.LinearTriInterpolator(T, z) 

j = numpy.complex(0, 1) 

from .parametric_surface import ParametricSurface 

def g(x, y): 

z = f(x, y) 

return (x, y, z) 

G = ParametricSurface(g, (list(numpy.r_[xmin:xmax:num_points*j]), list(numpy.r_[ymin:ymax:num_points*j])), texture=texture, **kwds) 

G._set_extra_kwds(kwds) 

return G 

 

if interpolation_type == 'clough' or interpolation_type =='default': 

 

points=[[x[i],y[i]] for i in range(len(x))] 

j = numpy.complex(0, 1) 

f = interpolate.CloughTocher2DInterpolator(points,z) 

from .parametric_surface import ParametricSurface 

def g(x, y): 

z = f([x, y]) 

return (x, y, z) 

G = ParametricSurface(g, (list(numpy.r_[xmin:xmax:num_points*j]), list(numpy.r_[ymin:ymax:num_points*j])), texture=texture, **kwds) 

G._set_extra_kwds(kwds) 

return G 

 

if interpolation_type == 'spline': 

from .plot3d import plot3d 

kx = kwds['kx'] if 'kx' in kwds else 3 

ky = kwds['ky'] if 'ky' in kwds else 3 

if 'degree' in kwds: 

kx = kwds['degree'] 

ky = kwds['degree'] 

s = kwds['smoothing'] if 'smoothing' in kwds else len(x)-numpy.sqrt(2*len(x)) 

s = interpolate.bisplrep(x, y, z, [int(1)]*len(x), xmin, xmax, ymin, ymax, kx=kx, ky=ky, s=s) 

f = lambda x,y: interpolate.bisplev(x, y, s) 

return plot3d(f, (xmin, xmax), (ymin, ymax), texture=texture, plot_points=[num_points, num_points], **kwds)