Skip to content

Commit

Permalink
Merge pull request #356 from python-adaptive/transparent-logo
Browse files Browse the repository at this point in the history
WIP: Add transparent logo (for dark mode)
  • Loading branch information
basnijholt committed Sep 5, 2022
2 parents 353b31e + 79df0ce commit f5f5e9d
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 23 deletions.
2 changes: 1 addition & 1 deletion docs/environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ dependencies:
- myst-nb=0.16.0
- sphinx_fontawesome=0.0.6
- sphinx=4.2.0
- ffmpeg=4.3.2
- ffmpeg=5.1.1
- cloudpickle
- loky
- furo
Expand Down
2 changes: 1 addition & 1 deletion docs/source/algorithms_and_examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ def get_hm(loss_per_interval, N=101):
plots = {n: plot(learner, n) for n in range(N)}
return hv.HoloMap(plots, kdims=["npoints"])
plot_homo = get_hm(uniform_loss).relabel("homogeneous samping")
plot_homo = get_hm(uniform_loss).relabel("homogeneous sampling")
plot_adaptive = get_hm(default_loss).relabel("with adaptive")
layout = plot_homo + plot_adaptive
layout.opts(plot=dict(toolbar=None))
Expand Down
133 changes: 112 additions & 21 deletions docs/source/logo.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
---
kernelspec:
name: python3
display_name: python3
jupytext:
text_representation:
extension: .md
format_name: myst
format_version: '0.13'
jupytext_version: 1.13.8
format_version: 0.13
jupytext_version: 1.14.1
kernelspec:
display_name: Python 3 (ipykernel)
language: python
name: python3
---

```{code-cell} ipython3
:tags: [remove-input]
import os
import functools
import subprocess
import tempfile
from pathlib import Path
import matplotlib.tri as mtri
import numpy as np
Expand All @@ -26,7 +31,8 @@ from tqdm.auto import tqdm
import adaptive
def add_rounded_corners(size, rad):
@functools.lru_cache
def make_cut(size, rad):
# Make new images
circle = Image.new("L", (rad * 2, rad * 2), color=1)
draw = ImageDraw.Draw(circle)
Expand All @@ -41,7 +47,12 @@ def add_rounded_corners(size, rad):
alpha.paste(circle.crop((rad, rad, rad * 2, rad * 2)), (w - rad, h - rad))
# To array
cut = np.array(alpha)
return np.array(alpha)
@functools.lru_cache
def add_rounded_corners(size=(1000, 1000), rad=300):
cut = make_cut(size, rad)
cut = cut.reshape((*cut.shape, 1)).repeat(4, axis=2)
# Set the corners to (252, 252, 252, 255) to match the RTD background #FCFCFC
Expand All @@ -50,6 +61,16 @@ def add_rounded_corners(size, rad):
return cut
def remove_rounded_corners(fname):
im = Image.open(fname)
ar = np.array(im)
cut = make_cut(size=ar.shape[:-1], rad=round(ar.shape[0] * 0.3)).astype(bool)
ar[:, :, -1] = np.where(~cut, ar[:, :, -1], 0)
im_new = Image.fromarray(ar)
im_new.save(fname)
return im_new
def learner_till(till, learner, data):
new_learner = adaptive.Learner2D(None, bounds=learner.bounds)
new_learner.data = {k: v for k, v in data[:till]}
Expand All @@ -61,7 +82,7 @@ def learner_till(till, learner, data):
def plot_tri(learner, ax):
tri = learner.ip().tri
triang = mtri.Triangulation(*tri.points.T, triangles=tri.vertices)
triang = mtri.Triangulation(*tri.points.T, triangles=tri.simplices)
return ax.triplot(triang, c="k", lw=0.8, alpha=0.8)
Expand All @@ -70,10 +91,14 @@ def get_new_artists(npoints, learner, data, rounded_corners, ax):
line1, line2 = plot_tri(new_learner, ax)
data = np.rot90(new_learner.interpolated_on_grid()[-1])
im = ax.imshow(data, extent=(-0.5, 0.5, -0.5, 0.5), cmap="viridis")
im2 = ax.imshow(rounded_corners, extent=(-0.5, 0.5, -0.5, 0.5), zorder=10)
return im, line1, line2, im2
if rounded_corners is None:
return im, line1, line2
else:
im2 = ax.imshow(rounded_corners, extent=(-0.5, 0.5, -0.5, 0.5), zorder=10)
return im, line1, line2, im2
@functools.lru_cache
def create_and_run_learner():
def ring(xy):
import numpy as np
Expand All @@ -87,11 +112,7 @@ def create_and_run_learner():
return learner
def main(fname="source/_static/logo_docs.mp4"):
learner = create_and_run_learner()
data = list(learner.data.items())
def get_figure():
fig, ax = plt.subplots(figsize=(5, 5))
fig.subplots_adjust(left=0, bottom=0, right=1, top=1, wspace=None, hspace=None)
ax.set_xticks([])
Expand All @@ -100,29 +121,99 @@ def main(fname="source/_static/logo_docs.mp4"):
ax.spines["right"].set_visible(False)
ax.spines["bottom"].set_visible(False)
ax.spines["left"].set_visible(False)
return fig, ax
def setup(nseconds=15):
learner = create_and_run_learner()
data = list(learner.data.items())
fig, ax = get_figure()
nseconds = 15
npoints = (len(data) * np.linspace(0, 1, 24 * nseconds) ** 2).astype(int)
rounded_corners = add_rounded_corners(size=(1000, 1000), rad=300)
return npoints, learner, data, rounded_corners, fig, ax
def animate_mp4(fname="source/_static/logo_docs.mp4", nseconds=15):
npoints, learner, data, rounded_corners, fig, ax = setup()
artists = [
get_new_artists(n, learner, data, rounded_corners, ax) for n in tqdm(npoints)
]
ani = animation.ArtistAnimation(fig, artists, blit=True)
ani.save(fname, writer=FFMpegWriter(fps=24))
def animate_png(folder=None, nseconds=15):
npoints, learner, data, rounded_corners, fig, ax = setup(nseconds)
if folder is None:
folder = Path(tempfile.gettempdir()) / next(tempfile._get_candidate_names())
folder = Path(folder)
folder.mkdir(parents=True, exist_ok=True)
fnames = []
ims = []
for i, n in tqdm(enumerate(npoints), total=len(npoints)):
fname = folder / f"logo_docs_{i:07d}.png"
fnames.append(fname)
npoints, learner, data, _, fig, ax = setup(nseconds)
get_new_artists(n, learner, data, None, ax)
fig.savefig(fname, transparent=True)
ax.cla()
plt.close(fig)
im = remove_rounded_corners(fname)
ims.append(im)
return fnames, ims
def save_webp(fname_webp, ims):
(im, *_ims) = ims
im.save(
fname_webp,
save_all=True,
append_images=_ims,
opimize=False,
durarion=2,
quality=70,
)
def save_webm(fname, fnames):
args = [
"ffmpeg",
"-framerate",
"24",
"-f",
"image2",
"-i",
str(fnames[0]).replace("0000000", "%07d"),
"-c:v",
"libvpx-vp9",
"-pix_fmt",
"yuva420p",
"-crf",
"23", # 0 is lossless 51 is worst
"-y",
fname,
]
return subprocess.run(args, capture_output=True)
if __name__ == "__main__":
fname = "_static/logo_docs.mp4"
if not os.path.exists(fname):
main(fname)
fname_mp4 = Path("_static/logo_docs.mp4")
# if not fname_mp4.exists():
# animate_mp4(fname_mp4)
fname_webm = fname_mp4.with_suffix(".webm")
if not fname_webm.exists():
fnames, ims = animate_png()
save_webm(fname_webm, fnames)
```

```{eval-rst}
.. raw:: html
<video autoplay loop muted playsinline webkit-playsinline
style="width: 400px; max-width: 100%; margin: 0 auto; display:block;">
<source src="_static/logo_docs.mp4" type="video/mp4">
<source src="_static/logo_docs.webm" type="video/mp4">
</video><br>
```

0 comments on commit f5f5e9d

Please sign in to comment.