Skip to content

Commit

Permalink
Create anywidget
Browse files Browse the repository at this point in the history
  • Loading branch information
manzt committed Mar 1, 2024
1 parent 5704ebe commit eaacac9
Show file tree
Hide file tree
Showing 19 changed files with 1,272 additions and 486 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
node_modules/
dist/
__pycache__
.ipynb_checkpoints/

/src/eigen_tour/static/
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,24 @@ visualizing (normalized) eigenvectors with the [Grand Tour](https://doi.org/10.1

## development

Create a python dev envrionment

```sh
hatch shell
```

Run the JavaScript development server:
```
pnpm install
pnpm dev
```

Open JupyterLab:

```sh
ANYWIDGET_HMR=1 juptyer lab
```

## data

Preparing a dataset for the visualization requires serializing a table to [Arrow IPC Format](https://arrow.apache.org/docs/python/ipc.html).
Expand Down
291 changes: 291 additions & 0 deletions demo.ipynb

Large diffs are not rendered by default.

File renamed without changes.
File renamed without changes.
30 changes: 15 additions & 15 deletions src/Overlay.ts → js/Overlay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export class Overlay {
.attr("min", renderer.epochs[0])
.attr("max", renderer.epochs[renderer.epochs.length - 1])
.attr("value", renderer.epochIndex)
.on("input", function () {
.on("input", function() {
let value = d3.select(this).property("value");
renderer.shouldAutoNextEpoch = false;
renderer.setEpochIndex(parseInt(value));
Expand All @@ -42,15 +42,15 @@ export class Overlay {
.attr(
"class",
"play-button tooltip fa " +
(renderer.shouldAutoNextEpoch ? "fa-pause" : "fa-play"),
(renderer.shouldAutoNextEpoch ? "fa-pause" : "fa-play"),
)
.on("mouseover", function () {
.on("mouseover", function() {
d3.select(this).style("opacity", 1);
})
.on("mouseout", function () {
.on("mouseout", function() {
d3.select(this).style("opacity", 0.7);
})
.on("click", function () {
.on("click", function() {
renderer.shouldAutoNextEpoch = !renderer.shouldAutoNextEpoch;
if (renderer.shouldAutoNextEpoch) {
d3.select(this).attr("class", "tooltip play-button fa fa-pause");
Expand All @@ -72,13 +72,13 @@ export class Overlay {
this.fullScreenButton = this.figure
.insert("i", ":first-child")
.attr("class", "tooltip teaser-fullscreenButton fas fa-expand-arrows-alt")
.on("mouseover", function () {
.on("mouseover", function() {
d3.select(this).style("opacity", 0.7);
})
.on("mouseout", function () {
.on("mouseout", function() {
d3.select(this).style("opacity", renderer.isFullScreen ? 0.7 : 0.3);
})
.on("click", function () {
.on("click", function() {
renderer.setFullScreen(!renderer.isFullScreen);
d3.select(this).style("opacity", renderer.isFullScreen ? 0.7 : 0.3);
});
Expand All @@ -93,10 +93,10 @@ export class Overlay {
.attr("width", 32)
.attr("height", 32)
.style("opacity", renderer.shouldPlayGrandTour ? 0.7 : 0.3)
.on("mouseover", function () {
.on("mouseover", function() {
d3.select(this).style("opacity", 0.7);
})
.on("mouseout", function () {
.on("mouseout", function() {
d3.select(this).style(
"opacity",
renderer.shouldPlayGrandTour ? 0.7 : 0.3,
Expand All @@ -108,7 +108,7 @@ export class Overlay {
.text("Pause Grand Tour");

this.grandtourButton
.on("click", function () {
.on("click", function() {
renderer.shouldPlayGrandTour = !renderer.shouldPlayGrandTour;
renderer.shouldCentralizeOrigin = renderer.shouldPlayGrandTour;

Expand Down Expand Up @@ -136,7 +136,7 @@ export class Overlay {
.attr("class", "overlay")
.attr("width", this.width)
.attr("height", this.height)
.on("dblclick", function () {
.on("dblclick", function() {
// renderer.shouldPlayGrandTour = !renderer.shouldPlayGrandTour;
})
.on("mousemove", () => {
Expand Down Expand Up @@ -248,7 +248,7 @@ export class Overlay {
renderer.shouldPlayGrandTour = false;
renderer.isDragging = true;
})
.on("drag", function (event) {
.on("drag", function(event) {
if (!renderer.gt) return;
let dx = renderer.sx.invert(event.dx) - renderer.sx.invert(0);
let dy = renderer.sy.invert(event.dy) - renderer.sy.invert(0);
Expand All @@ -260,7 +260,7 @@ export class Overlay {
renderer.gt.setMatrix(matrix);
self.redrawAxis();
})
.on("end", function () {
.on("end", function() {
renderer.isDragging = false;
renderer.shouldPlayGrandTour = renderer.shouldPlayGrandTourPrev ??
false;
Expand All @@ -284,7 +284,7 @@ export class Overlay {
redrawAxis() {
if (this.renderer.gt === undefined) return;
let { ndim = 10 } = this.renderer.dataObj ?? {};
let identity = Array.from({ length: ndim }, (_, i) => {
let identity = Array.from({ length: ndim }, (_, i) => {
return Array.from({ length: ndim }, (_, j) => i === j ? 1 : 0)
})
let handlePos = this.renderer.gt.project(identity);
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
12 changes: 11 additions & 1 deletion src/utils.ts → js/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as d3 from "d3";
import * as math from "mathjs";
import numeric from "numeric";

import type { Scale } from "./types";

Expand Down Expand Up @@ -435,3 +434,14 @@ export function zip<A, B>(a: A[], b: B[]): [A, B][] {
}
return out;
}

export function loadScript(url: string): Promise<void> {
return new Promise((resolve, reject) => {
let script = document.createElement("script");
script.type = "text/javascript";
script.src = url;
script.onload = () => resolve();
script.onerror = (err) => reject(err);
document.head.appendChild(script);
});
}
3 changes: 1 addition & 2 deletions styles/style.css → js/widget.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

d-title p{
border-bottom: solid 1px rgba(0, 0, 0, 0.1);
}
Expand Down Expand Up @@ -334,7 +333,6 @@ canvas.smallmultiple0{
}



.overlay{
position: absolute;
}
Expand Down Expand Up @@ -488,3 +486,4 @@ figcaption > span:before{
background: white;
opacity: 0.8;
}

49 changes: 49 additions & 0 deletions js/widget.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import type { RenderProps } from "@anywidget/types";

import { Renderer } from "./Renderer";
import * as utils from "./utils";
import fs from "./shaders/teaser_fragment.glsl";
import vs from "./shaders/teaser_vertex.glsl";

import "./widget.css";

interface Model {
data: DataView
}

const template = `<d-figure class="teaser">
<canvas id="teaser"></canvas>
</d-figure>
`

export default {
async render({ model, el }: RenderProps<Model>) {
el.innerHTML = template;
let canvas = el.querySelector("canvas")!;
console.log("initGL");
let { gl, program } = utils.initGL(canvas, fs, vs);
let renderer = new Renderer(gl, program);
renderer.overlay.fullScreenButton.style("top", "18px");
renderer.overlay.epochSlider.style("top", "calc(100% - 28px)");
renderer.overlay.playButton.style("top", "calc(100% - 34px)");
renderer.overlay.grandtourButton.style("top", "calc(100% - 34px)");

console.log("model", model);
{
// load the data
let clearBanner = utils.createLoadingBanner(renderer.overlay.figure);
console.log("loading data");
await renderer.initData(model.get("data").buffer);
console.log("data loaded");
clearBanner();
}

function onResize() {
renderer.setFullScreen(renderer.isFullScreen);
}
window.addEventListener("resize", onResize);
return () => {
window.removeEventListener("resize", onResize);
}
}
}
11 changes: 5 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@
"name": "eigen-tour",
"version": "0.0.0",
"scripts": {
"dev": "vite --port 3000",
"build": "vite build",
"preview": "vite preview",
"check": "tsc --noEmit",
"dev": "npm run build -- --sourcemap=inline --watch",
"build": "esbuild js/widget.ts --minify --format=esm --bundle --outdir=src/eigen_tour/static",
"fmt": "deno fmt --ignore=dist,node_modules --options-use-tabs"
},
"author": "Trevor Manz",
"license": "MIT",
"dependencies": {
"@anywidget/types": "^0.1.5",
"@types/d3": "^7.4.0",
"@types/numeric": "^1.2.2",
"apache-arrow": "^9.0.0",
Expand All @@ -20,7 +19,7 @@
"numeric": "^1.2.6"
},
"devDependencies": {
"typescript": "^4.7.4",
"vite": "^3.0.4"
"esbuild": "^0.20.1",
"typescript": "^5.3.3"
}
}
Loading

0 comments on commit eaacac9

Please sign in to comment.