1
1
---
2
- kernelspec :
3
- name : python3
4
- display_name : python3
5
2
jupytext :
6
3
text_representation :
7
4
extension : .md
8
5
format_name : myst
9
- format_version : ' 0.13'
10
- jupytext_version : 1.13.8
6
+ format_version : 0.13
7
+ jupytext_version : 1.14.1
8
+ kernelspec :
9
+ display_name : Python 3 (ipykernel)
10
+ language : python
11
+ name : python3
11
12
---
12
13
13
14
``` {code-cell} ipython3
14
15
:tags: [remove-input]
15
16
16
17
import os
18
+ import functools
19
+ import subprocess
20
+ import tempfile
21
+ from pathlib import Path
17
22
18
23
import matplotlib.tri as mtri
19
24
import numpy as np
@@ -26,7 +31,8 @@ from tqdm.auto import tqdm
26
31
import adaptive
27
32
28
33
29
- def add_rounded_corners(size, rad):
34
+ @functools.lru_cache
35
+ def make_cut(size, rad):
30
36
# Make new images
31
37
circle = Image.new("L", (rad * 2, rad * 2), color=1)
32
38
draw = ImageDraw.Draw(circle)
@@ -41,7 +47,12 @@ def add_rounded_corners(size, rad):
41
47
alpha.paste(circle.crop((rad, rad, rad * 2, rad * 2)), (w - rad, h - rad))
42
48
43
49
# To array
44
- cut = np.array(alpha)
50
+ return np.array(alpha)
51
+
52
+
53
+ @functools.lru_cache
54
+ def add_rounded_corners(size=(1000, 1000), rad=300):
55
+ cut = make_cut(size, rad)
45
56
cut = cut.reshape((*cut.shape, 1)).repeat(4, axis=2)
46
57
47
58
# Set the corners to (252, 252, 252, 255) to match the RTD background #FCFCFC
@@ -50,6 +61,16 @@ def add_rounded_corners(size, rad):
50
61
return cut
51
62
52
63
64
+ def remove_rounded_corners(fname):
65
+ im = Image.open(fname)
66
+ ar = np.array(im)
67
+ cut = make_cut(size=ar.shape[:-1], rad=round(ar.shape[0] * 0.3)).astype(bool)
68
+ ar[:, :, -1] = np.where(~cut, ar[:, :, -1], 0)
69
+ im_new = Image.fromarray(ar)
70
+ im_new.save(fname)
71
+ return im_new
72
+
73
+
53
74
def learner_till(till, learner, data):
54
75
new_learner = adaptive.Learner2D(None, bounds=learner.bounds)
55
76
new_learner.data = {k: v for k, v in data[:till]}
@@ -61,7 +82,7 @@ def learner_till(till, learner, data):
61
82
62
83
def plot_tri(learner, ax):
63
84
tri = learner.ip().tri
64
- triang = mtri.Triangulation(*tri.points.T, triangles=tri.vertices )
85
+ triang = mtri.Triangulation(*tri.points.T, triangles=tri.simplices )
65
86
return ax.triplot(triang, c="k", lw=0.8, alpha=0.8)
66
87
67
88
@@ -70,10 +91,14 @@ def get_new_artists(npoints, learner, data, rounded_corners, ax):
70
91
line1, line2 = plot_tri(new_learner, ax)
71
92
data = np.rot90(new_learner.interpolated_on_grid()[-1])
72
93
im = ax.imshow(data, extent=(-0.5, 0.5, -0.5, 0.5), cmap="viridis")
73
- im2 = ax.imshow(rounded_corners, extent=(-0.5, 0.5, -0.5, 0.5), zorder=10)
74
- return im, line1, line2, im2
94
+ if rounded_corners is None:
95
+ return im, line1, line2
96
+ else:
97
+ im2 = ax.imshow(rounded_corners, extent=(-0.5, 0.5, -0.5, 0.5), zorder=10)
98
+ return im, line1, line2, im2
75
99
76
100
101
+ @functools.lru_cache
77
102
def create_and_run_learner():
78
103
def ring(xy):
79
104
import numpy as np
@@ -87,11 +112,7 @@ def create_and_run_learner():
87
112
return learner
88
113
89
114
90
- def main(fname="source/_static/logo_docs.mp4"):
91
- learner = create_and_run_learner()
92
-
93
- data = list(learner.data.items())
94
-
115
+ def get_figure():
95
116
fig, ax = plt.subplots(figsize=(5, 5))
96
117
fig.subplots_adjust(left=0, bottom=0, right=1, top=1, wspace=None, hspace=None)
97
118
ax.set_xticks([])
@@ -100,29 +121,99 @@ def main(fname="source/_static/logo_docs.mp4"):
100
121
ax.spines["right"].set_visible(False)
101
122
ax.spines["bottom"].set_visible(False)
102
123
ax.spines["left"].set_visible(False)
124
+ return fig, ax
125
+
126
+
127
+ def setup(nseconds=15):
128
+ learner = create_and_run_learner()
129
+
130
+ data = list(learner.data.items())
131
+
132
+ fig, ax = get_figure()
103
133
104
- nseconds = 15
105
134
npoints = (len(data) * np.linspace(0, 1, 24 * nseconds) ** 2).astype(int)
106
135
rounded_corners = add_rounded_corners(size=(1000, 1000), rad=300)
136
+ return npoints, learner, data, rounded_corners, fig, ax
137
+
138
+
139
+ def animate_mp4(fname="source/_static/logo_docs.mp4", nseconds=15):
140
+ npoints, learner, data, rounded_corners, fig, ax = setup()
107
141
artists = [
108
142
get_new_artists(n, learner, data, rounded_corners, ax) for n in tqdm(npoints)
109
143
]
110
-
111
144
ani = animation.ArtistAnimation(fig, artists, blit=True)
112
145
ani.save(fname, writer=FFMpegWriter(fps=24))
113
146
114
147
148
+ def animate_png(folder=None, nseconds=15):
149
+ npoints, learner, data, rounded_corners, fig, ax = setup(nseconds)
150
+ if folder is None:
151
+ folder = Path(tempfile.gettempdir()) / next(tempfile._get_candidate_names())
152
+ folder = Path(folder)
153
+ folder.mkdir(parents=True, exist_ok=True)
154
+ fnames = []
155
+ ims = []
156
+ for i, n in tqdm(enumerate(npoints), total=len(npoints)):
157
+ fname = folder / f"logo_docs_{i:07d}.png"
158
+ fnames.append(fname)
159
+ npoints, learner, data, _, fig, ax = setup(nseconds)
160
+ get_new_artists(n, learner, data, None, ax)
161
+ fig.savefig(fname, transparent=True)
162
+ ax.cla()
163
+ plt.close(fig)
164
+ im = remove_rounded_corners(fname)
165
+ ims.append(im)
166
+ return fnames, ims
167
+
168
+
169
+ def save_webp(fname_webp, ims):
170
+ (im, *_ims) = ims
171
+ im.save(
172
+ fname_webp,
173
+ save_all=True,
174
+ append_images=_ims,
175
+ opimize=False,
176
+ durarion=2,
177
+ quality=70,
178
+ )
179
+
180
+
181
+ def save_webm(fname, fnames):
182
+ args = [
183
+ "ffmpeg",
184
+ "-framerate",
185
+ "24",
186
+ "-f",
187
+ "image2",
188
+ "-i",
189
+ str(fnames[0]).replace("0000000", "%07d"),
190
+ "-c:v",
191
+ "libvpx-vp9",
192
+ "-pix_fmt",
193
+ "yuva420p",
194
+ "-crf",
195
+ "23", # 0 is lossless 51 is worst
196
+ "-y",
197
+ fname,
198
+ ]
199
+ return subprocess.run(args, capture_output=True)
200
+
201
+
115
202
if __name__ == "__main__":
116
- fname = "_static/logo_docs.mp4"
117
- if not os.path.exists(fname):
118
- main(fname)
203
+ fname_mp4 = Path("_static/logo_docs.mp4")
204
+ # if not fname_mp4.exists():
205
+ # animate_mp4(fname_mp4)
206
+ fname_webm = fname_mp4.with_suffix(".webm")
207
+ if not fname_webm.exists():
208
+ fnames, ims = animate_png()
209
+ save_webm(fname_webm, fnames)
119
210
```
120
211
121
212
``` {eval-rst}
122
213
.. raw:: html
123
214
124
215
<video autoplay loop muted playsinline webkit-playsinline
125
216
style="width: 400px; max-width: 100%; margin: 0 auto; display:block;">
126
- <source src="_static/logo_docs.mp4 " type="video/mp4">
217
+ <source src="_static/logo_docs.webm " type="video/mp4">
127
218
</video><br>
128
219
```
0 commit comments