Skip to content

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")
No description has been provided for this image

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 &gt;= .5
    im = skimage.morphology.skeletonize(im)
    df = DataFrame(im)
    series = df.stack()[df.stack() &gt; .5]

    df = DataFrame(map(list, series.index.values), columns=list("yx"))
    df.T
0 1 2 3 4 5 6 7 8 9 ... 663 664 665 666 667 668 669 670 671 672
y 325 325 326 326 326 326 326 326 326 326 ... 423 424 424 424 424 425 425 425 426 426
x 126 127 114 115 116 117 118 119 120 121 ... 362 363 364 365 366 367 368 369 370 371

2 rows × 673 columns

%%
## 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>
```

css styling for the letters

css=\
<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>
```

camera selection

select a camera or direction to activate the video streaming in the points.


html =\
<form name=one class=webcam>
    <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()

a fuck in plot

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")
<Axes: xlabel='x', ylabel='y'>
No description has been provided for this image