1
- # -*- coding: utf-8 -*-
1
+ # sage.doctest: optional - sage.symbolic
2
2
r"""
3
3
Animated plots
4
4
31
31
The sine function::
32
32
33
33
sage: x = SR.var("x")
34
- sage: sines = [plot(c*sin(x), (-2*pi,2*pi), color=Color(c,0,0), ymin=-1, ymax=1) for c in sxrange(0,1,.2)]
34
+ sage: sines = [plot(c*sin(x), (-2*pi,2*pi), color=Color(c,0,0), ymin=-1, ymax=1)
35
+ ....: for c in sxrange(0,1,.2)]
35
36
sage: a = animate(sines)
36
37
sage: print(a)
37
38
Animation with 5 frames
48
49
49
50
An animated :class:`sage.plot.multigraphics.GraphicsArray` of rotating ellipses::
50
51
51
- sage: E = animate((graphics_array([[ellipse((0,0),a,b,angle=t,xmin=-3,xmax=3)+circle((0,0),3,color='blue') for a in range(1,3)] for b in range(2,4)]) for t in sxrange(0,pi/4,.15)))
52
+ sage: E = animate((graphics_array([[ellipse((0,0), a, b, angle=t, xmin=-3, xmax=3)
53
+ ....: + circle((0,0), 3, color='blue')
54
+ ....: for a in range(1,3)]
55
+ ....: for b in range(2,4)])
56
+ ....: for t in sxrange(0, pi/4, .15)))
52
57
sage: str(E) # animations produced from a generator do not have a known length
53
58
'Animation with unknown number of frames'
54
59
sage: E.show() # long time # optional -- ImageMagick
55
60
56
61
A simple animation of a circle shooting up to the right::
57
62
58
- sage: c = animate([circle((i,i), 1-1/(i+1), hue=i/10) for i in srange(0,2,0.2)],
59
- ....: xmin=0,ymin=0,xmax=2,ymax=2,figsize=[2,2])
63
+ sage: c = animate([circle((i,i), 1 - 1/(i+1), hue=i/10)
64
+ ....: for i in srange(0, 2, 0.2)],
65
+ ....: xmin=0, ymin=0, xmax=2, ymax=2, figsize=[2,2])
60
66
sage: c.show() # long time # optional -- ImageMagick
61
67
62
68
63
69
Animations of 3d objects::
64
70
65
71
sage: s,t = SR.var("s,t")
66
72
sage: def sphere_and_plane(x):
67
- ....: return sphere((0,0,0),1,color='red',opacity=.5)+parametric_plot3d([t,x,s],(s,-1,1),(t,-1,1),color='green',opacity=.7)
68
- sage: sp = animate([sphere_and_plane(x) for x in sxrange(-1,1,.3)])
73
+ ....: return (sphere((0,0,0), 1, color='red', opacity=.5)
74
+ ....: + parametric_plot3d([t,x,s], (s,-1,1), (t,-1,1),
75
+ ....: color='green', opacity=.7))
76
+ sage: sp = animate([sphere_and_plane(x)
77
+ ....: for x in sxrange(-1, 1, .3)])
69
78
sage: sp[0] # first frame
70
79
Graphics3d Object
71
80
sage: sp[-1] # last frame
74
83
75
84
sage: (x,y,z) = SR.var("x,y,z")
76
85
sage: def frame(t):
77
- ....: return implicit_plot3d((x^2 + y^2 + z^2), (x, -2, 2), (y, -2, 2), (z, -2, 2), plot_points=60, contour=[1,3,5], region=lambda x,y,z: x<=t or y>=t or z<=t)
78
- sage: a = animate([frame(t) for t in srange(.01,1.5,.2)])
79
- sage: a[0] # long time
86
+ ....: return implicit_plot3d((x^2 + y^2 + z^2),
87
+ ....: (x, -2, 2), (y, -2, 2), (z, -2, 2),
88
+ ....: plot_points=60, contour=[1,3,5],
89
+ ....: region=lambda x,y,z: x<=t or y>=t or z<=t)
90
+ sage: a = animate([frame(t)
91
+ ....: for t in srange(.01,1.5,.2)])
92
+ sage: a[0] # long time
80
93
Graphics3d Object
81
94
sage: a.show() # long time # optional -- ImageMagick
82
95
86
99
illustrated by the following example::
87
100
88
101
sage: t = SR.var("t")
89
- sage: a = animate((sin(c*pi*t) for c in sxrange(1,2,.2)))
102
+ sage: a = animate((sin(c*pi*t)
103
+ ....: for c in sxrange(1, 2, .2)))
90
104
sage: a.show() # long time # optional -- ImageMagick
91
105
92
106
@@ -135,7 +149,8 @@ def animate(frames, **kwds):
135
149
EXAMPLES::
136
150
137
151
sage: t = SR.var("t")
138
- sage: a = animate((cos(c*pi*t) for c in sxrange(1,2,.2)))
152
+ sage: a = animate((cos(c*pi*t)
153
+ ....: for c in sxrange(1, 2, .2)))
139
154
sage: a.show() # long time # optional -- ImageMagick
140
155
141
156
See also :mod:`sage.plot.animate` for more examples.
@@ -149,22 +164,23 @@ class Animation(WithEqualityById, SageObject):
149
164
INPUT:
150
165
151
166
152
- - ``v`` - iterable of Sage objects. These should preferably be
153
- graphics objects, but if they aren't then :meth:`make_image` is
167
+ - ``v`` -- iterable of Sage objects. These should preferably be
168
+ graphics objects, but if they aren't, then :meth:`make_image` is
154
169
called on them.
155
170
156
- - ``xmin, xmax, ymin, ymax`` - the ranges of the x and y axes.
171
+ - ``xmin, xmax, ymin, ymax`` -- the ranges of the x and y axes.
157
172
158
- - ``**kwds`` - all additional inputs are passed onto the rendering
159
- command. E.g., use figsize to adjust the resolution and aspect
173
+ - ``**kwds`` -- all additional inputs are passed onto the rendering
174
+ command. E.g., use `` figsize`` to adjust the resolution and aspect
160
175
ratio.
161
176
162
177
163
178
EXAMPLES::
164
179
165
180
sage: x = SR.var("x")
166
- sage: a = animate([sin(x + float(k)) for k in srange(0,2*pi,0.3)],
167
- ....: xmin=0, xmax=2*pi, figsize=[2,1])
181
+ sage: a = animate([sin(x + float(k))
182
+ ....: for k in srange(0, 2*pi, 0.3)],
183
+ ....: xmin=0, xmax=2*pi, figsize=[2,1])
168
184
sage: print(a)
169
185
Animation with 21 frames
170
186
sage: print(a[:5])
@@ -185,9 +201,9 @@ class Animation(WithEqualityById, SageObject):
185
201
sage: step = 0.1
186
202
sage: L = Graphics()
187
203
sage: v = []
188
- sage: for i in srange(0,1, step):
189
- ....: L += line([(i,i^2),(i+step,(i+step)^2)], rgbcolor=(1,0,0), thickness=2)
190
- ....: v.append(L)
204
+ sage: for i in srange(0, 1, step):
205
+ ....: L += line([(i,i^2),(i+step,(i+step)^2)], rgbcolor=(1,0,0), thickness=2)
206
+ ....: v.append(L)
191
207
sage: a = animate(v, xmin=0, ymin=0)
192
208
sage: a.show() # long time # optional -- ImageMagick
193
209
sage: show(L)
@@ -427,7 +443,9 @@ def make_image(self, frame, filename, **kwds):
427
443
sage: t = SR.var("t")
428
444
sage: x = lambda t: cos(t)
429
445
sage: y = lambda n,t: sin(t)/n
430
- sage: B = MyAnimation([([x(t), y(i+1,t)],(t,0,1), {'color':Color((1,0,i/4)), 'aspect_ratio':1, 'ymax':1}) for i in range(4)])
446
+ sage: B = MyAnimation([([x(t), y(i+1,t)], (t,0,1),
447
+ ....: {'color':Color((1,0,i/4)), 'aspect_ratio':1, 'ymax':1})
448
+ ....: for i in range(4)])
431
449
432
450
sage: d = B.png(); v = os.listdir(d); v.sort(); v # long time
433
451
['00000000.png', '00000001.png', '00000002.png', '00000003.png']
@@ -436,10 +454,12 @@ def make_image(self, frame, filename, **kwds):
436
454
sage: class MyAnimation(Animation):
437
455
....: def make_image(self, frame, filename, **kwds):
438
456
....: G = frame.plot()
439
- ....: G.set_axes_range(floor(G.xmin()),ceil(G.xmax()),floor(G.ymin()),ceil(G.ymax()))
457
+ ....: G.set_axes_range(floor(G.xmin()), ceil(G.xmax()),
458
+ ....: floor(G.ymin()), ceil(G.ymax()))
440
459
....: G.save_image(filename, **kwds)
441
460
442
- sage: B = MyAnimation([graphs.CompleteGraph(n) for n in range(7,11)], figsize=5)
461
+ sage: B = MyAnimation([graphs.CompleteGraph(n)
462
+ ....: for n in range(7,11)], figsize=5)
443
463
sage: d = B.png()
444
464
sage: v = os.listdir(d); v.sort(); v
445
465
['00000000.png', '00000001.png', '00000002.png', '00000003.png']
@@ -506,26 +526,27 @@ def graphics_array(self, ncols=3):
506
526
507
527
EXAMPLES::
508
528
509
- sage: E = EllipticCurve('37a')
510
- sage: v = [E.change_ring(GF(p)).plot(pointsize=30) for p in [97, 101, 103]]
511
- sage: a = animate(v, xmin=0, ymin=0, axes=False)
512
- sage: print(a)
529
+ sage: E = EllipticCurve('37a') # optional - sage.schemes
530
+ sage: v = [E.change_ring(GF(p)).plot(pointsize=30) # optional - sage.rings.finite_rings sage.schemes
531
+ ....: for p in [97, 101, 103]]
532
+ sage: a = animate(v, xmin=0, ymin=0, axes=False) # optional - sage.rings.finite_rings sage.schemes
533
+ sage: print(a) # optional - sage.rings.finite_rings sage.schemes
513
534
Animation with 3 frames
514
- sage: a.show() # optional -- ImageMagick
535
+ sage: a.show() # optional -- ImageMagick # optional - sage.rings.finite_rings sage.schemes
515
536
516
537
Modify the default arrangement of array::
517
538
518
- sage: g = a.graphics_array(); print(g)
539
+ sage: g = a.graphics_array(); print(g) # optional - sage.rings.finite_rings sage.schemes
519
540
Graphics Array of size 1 x 3
520
- sage: g.show(figsize=[6,3])
541
+ sage: g.show(figsize=[6,3]) # optional - sage.rings.finite_rings sage.schemes
521
542
522
543
Specify different arrangement of array and save it with a given file name::
523
544
524
- sage: g = a.graphics_array(ncols=2); print(g)
545
+ sage: g = a.graphics_array(ncols=2); print(g) # optional - sage.rings.finite_rings sage.schemes
525
546
Graphics Array of size 2 x 2
526
- sage: f = tmp_filename(ext='.png'); print(f)
547
+ sage: f = tmp_filename(ext='.png'); print(f) # optional - sage.rings.finite_rings sage.schemes
527
548
...png
528
- sage: g.save(f)
549
+ sage: g.save(f) # optional - sage.rings.finite_rings sage.schemes
529
550
530
551
Frames can be specified as a generator too; it is internally converted to a list::
531
552
@@ -580,16 +601,21 @@ def gif(self, delay=20, savefile=None, iterations=0, show_path=False,
580
601
EXAMPLES::
581
602
582
603
sage: x = SR.var("x")
583
- sage: a = animate([sin(x + float(k)) for k in srange(0,2*pi,0.7)],
604
+ sage: a = animate([sin(x + float(k))
605
+ ....: for k in srange(0,2*pi,0.7)],
584
606
....: xmin=0, xmax=2*pi, ymin=-1, ymax=1, figsize=[2,1])
585
607
sage: td = tmp_dir()
586
608
sage: a.gif() # not tested
587
- sage: a.gif(savefile=td + 'my_animation.gif', delay=35, iterations=3) # long time # optional -- ImageMagick
588
- sage: with open(td + 'my_animation.gif', 'rb') as f: print(b'GIF8' in f.read()) # long time # optional -- ImageMagick
609
+ sage: a.gif(savefile=td + 'my_animation.gif', # long time # optional -- ImageMagick
610
+ ....: delay=35, iterations=3)
611
+ sage: with open(td + 'my_animation.gif', 'rb') as f: # long time # optional -- ImageMagick
612
+ ....: print(b'GIF8' in f.read())
589
613
True
590
- sage: a.gif(savefile=td + 'my_animation.gif', show_path=True) # long time # optional -- ImageMagick
614
+ sage: a.gif(savefile=td + 'my_animation.gif', # long time # optional -- ImageMagick
615
+ ....: show_path=True)
591
616
Animation saved to .../my_animation.gif.
592
- sage: a.gif(savefile=td + 'my_animation_2.gif', show_path=True, use_ffmpeg=True) # long time # optional -- ffmpeg
617
+ sage: a.gif(savefile=td + 'my_animation_2.gif', # long time # optional -- ffmpeg
618
+ ....: show_path=True, use_ffmpeg=True)
593
619
Animation saved to .../my_animation_2.gif.
594
620
595
621
.. NOTE::
@@ -810,8 +836,9 @@ def show(self, delay=None, iterations=None, **kwds):
810
836
EXAMPLES::
811
837
812
838
sage: x = SR.var("x")
813
- sage: a = animate([sin(x + float(k)) for k in srange(0,2*pi,0.7)],
814
- ....: xmin=0, xmax=2*pi, figsize=[2,1])
839
+ sage: a = animate([sin(x + float(k))
840
+ ....: for k in srange(0,2*pi,0.7)],
841
+ ....: xmin=0, xmax=2*pi, figsize=[2,1])
815
842
sage: a.show() # long time # optional -- ImageMagick
816
843
817
844
The preceding will loop the animation forever. If you want to show
@@ -922,7 +949,8 @@ def ffmpeg(self, savefile=None, show_path=False, output_format=None,
922
949
EXAMPLES::
923
950
924
951
sage: x = SR.var("x")
925
- sage: a = animate([sin(x + float(k)) for k in srange(0,2*pi,0.7)],
952
+ sage: a = animate([sin(x + float(k))
953
+ ....: for k in srange(0, 2*pi, 0.7)],
926
954
....: xmin=0, xmax=2*pi, ymin=-1, ymax=1, figsize=[2,1])
927
955
sage: td = tmp_dir()
928
956
sage: a.ffmpeg(savefile=td + 'new.mpg') # long time # optional -- ffmpeg
@@ -1042,8 +1070,9 @@ def apng(self, savefile=None, show_path=False, delay=20, iterations=0):
1042
1070
EXAMPLES::
1043
1071
1044
1072
sage: x = SR.var("x")
1045
- sage: a = animate([sin(x + float(k)) for k in srange(0,2*pi,0.7)],
1046
- ....: xmin=0, xmax=2*pi, figsize=[2,1])
1073
+ sage: a = animate([sin(x + float(k))
1074
+ ....: for k in srange(0,2*pi,0.7)],
1075
+ ....: xmin=0, xmax=2*pi, figsize=[2,1])
1047
1076
sage: dir = tmp_dir()
1048
1077
sage: a.apng(show_path=True) # long time
1049
1078
Animation saved to ....png.
@@ -1053,7 +1082,8 @@ def apng(self, savefile=None, show_path=False, delay=20, iterations=0):
1053
1082
1054
1083
If the individual frames have different sizes, an error will be raised::
1055
1084
1056
- sage: a = animate([plot(sin(x), (x, 0, k)) for k in range(1,4)],
1085
+ sage: a = animate([plot(sin(x), (x, 0, k))
1086
+ ....: for k in range(1,4)],
1057
1087
....: ymin=-1, ymax=1, aspect_ratio=1, figsize=[2,1])
1058
1088
sage: a.apng() # long time
1059
1089
Traceback (most recent call last):
@@ -1111,7 +1141,8 @@ def save(self, filename=None, show_path=False, use_ffmpeg=False, **kwds):
1111
1141
EXAMPLES::
1112
1142
1113
1143
sage: x = SR.var("x")
1114
- sage: a = animate([sin(x + float(k)) for k in srange(0,2*pi,0.7)],
1144
+ sage: a = animate([sin(x + float(k))
1145
+ ....: for k in srange(0, 2*pi, 0.7)],
1115
1146
....: xmin=0, xmax=2*pi, ymin=-1, ymax=1, figsize=[2,1])
1116
1147
sage: td = tmp_dir()
1117
1148
sage: a.save() # not tested
@@ -1194,7 +1225,8 @@ def interactive(self, **kwds):
1194
1225
EXAMPLES::
1195
1226
1196
1227
sage: x = SR.var("x")
1197
- sage: frames = [point3d((sin(x), cos(x), x)) for x in (0, pi/16, .., 2*pi)]
1228
+ sage: frames = [point3d((sin(x), cos(x), x))
1229
+ ....: for x in (0, pi/16, .., 2*pi)]
1198
1230
sage: animate(frames).interactive(online=True)
1199
1231
Graphics3d Object
1200
1232
@@ -1245,16 +1277,16 @@ class APngAssembler():
1245
1277
1246
1278
INPUT:
1247
1279
1248
- - ``out`` -- a file opened for binary writing to which the data
1249
- will be written
1280
+ - ``out`` -- a file opened for binary writing to which the data
1281
+ will be written
1250
1282
1251
- - ``num_frames`` -- the number of frames in the animation
1283
+ - ``num_frames`` -- the number of frames in the animation
1252
1284
1253
- - ``num_plays`` -- how often to iterate, 0 means infinitely
1285
+ - ``num_plays`` -- how often to iterate, 0 means infinitely
1254
1286
1255
- - ``delay`` -- numerator of the delay fraction in seconds
1287
+ - ``delay`` -- numerator of the delay fraction in seconds
1256
1288
1257
- - ``delay_denominator`` -- denominator of the delay in seconds
1289
+ - ``delay_denominator`` -- denominator of the delay in seconds
1258
1290
1259
1291
EXAMPLES::
1260
1292
0 commit comments