stream drawing words with video elements¤
in this stream we explore some recent visualization work and apply it to words/letters. we wind up with interactive letters composed of videos.
%%
<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" frameborder="0" height="315" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/1yMSyusdjMU?si=GUiYfUTfV_nB7eVj" title="YouTube video player" width="560"></iframe>
import matplotlib.pyplot
ax = matplotlib.pyplot.gca()
fig = matplotlib.pyplot.gcf()
ax.axis("off")
ax.text(0, 0, "fuck", size=100)
fig.savefig(file := "word.png")
modify the image with skimage
¤
import skimage.io, skimage.morphology, skimage.color
df = pandas.DataFrame()
im = 1-skimage.color.rgb2gray(skimage.io.imread(file)[:,:,:3]).round()
im >= .5
im = skimage.morphology.skeletonize(im)
df = DataFrame(im)
series = df.stack()[df.stack() > .5]
df = DataFrame(map(list, series.index.values), columns=list("yx"))
df.T
%%
## css styling for the letters
{{css.data}}
css=\
```html
<style>
#letters {
--width: 600px;
--height: 400px;
height: var(--height);
width: var(--width);
tbody {
position: relative;
tr {
display: block;
width: 2rem;
height: 2rem;
--dx: calc((var(--x) - var(--x_min))/(var(--x_max) - var(--x_min)));
--dy: calc((var(--y) - var(--y_min))/(var(--y_max) - var(--y_min)));
position: absolute;
border-radius: 100% 100%;
transform:
translateX(calc(var(--dx) * var(--width)))
translateY(calc(var(--dy) * var(--height)));
}
}
}
</style>
```
%%
## camera selection
select a camera or direction to activate the video streaming in the points.
{{html.data}}
html =\
```html
<form class="webcam" name="one">
<label for="camera">cameras</label>
<select name="camera"></select>
<select name="direction">
<option value="user">forward</option>
<option value="environment">back</option>
</select>
<br/>
<video autoplay=""></video>
</form>
<script>
Array.from(document.getElementsByClassName("webcam")).forEach(
(form) => {
let [video] = form.getElementsByTagName("video");
let camera = form.querySelector("[name=camera]");
let direction = form.querySelector("[name=direction]");
if (!navigator.mediaDevices?.enumerateDevices) {
console.log("enumerateDevices() not supported.");
} else {
navigator.mediaDevices
.enumerateDevices({video: true, audio: false})
.then((devices) => {
devices.forEach((device) => {updateVideoSources(device, camera)});
})
.catch((err) => {console.error(`${err.name}: ${err.message}`);});
}
function change(){
console.log("changing source");
navigator.mediaDevices.getUserMedia({
video: {
facingMode: form.elements.direction.value,
deviceId: {
exact: form.elements.camera.value
}
}, audio: false
})
.then((stream) => {
document.querySelectorAll(".cams").forEach(
video => video.srcObject = stream
)
})
.catch(console.log);
}
change();
camera.addEventListener("change", change);
direction.addEventListener("change", change);
}
)
function updateVideoSources(device, camera){
if (device.kind == "videoinput") {
let option = document.createElement('option');
if (!camera.querySelector(`[value="${device.deviceId}"]`)){
option.setAttribute("value", device.deviceId);
option.insertAdjacentHTML( 'beforeend', device.label || "unknown" );
camera.appendChild(option);
}
};
}
updateVideoSources()
</script>
```
%%
## a fuck in plot
{% set df= df.sample(175) %}
<table id="letters">
<tbody "_max")}}"="" _min")}}="" style="{{df.min().pipe(style_attrs, " {{df.max().pipe(style_attrs,="">
{% for i, row in df.iterrows() -%}<tr style="{{style_attrs(row)}}">
{%- for h in row.values %}<td hidden="">{{h}}</td>{% endfor %}
<td><video autoplay="" class="cams" height="50" width="50"></video></td>
</tr>{%- endfor %}
</tbody>
</table>
def style_attrs(row, post=""):
out = io.StringIO()
for k, v in row.items():
out.write("--"), out.write(k), out.write(post), out.write(": "), out.write(str(v)), out.write("; ")
return out.getvalue()
matplotlib view¤
df.plot.scatter(*"xy")