Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Jupyter comms server #145

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open

feat: Jupyter comms server #145

wants to merge 3 commits into from

Conversation

manzt
Copy link
Member

@manzt manzt commented Feb 16, 2024

Depends on higlass/higlass#1194. I have just got this working locally with Vite.

Screen Recording 2024-02-15 at 11 17 26 PM

@@ -1,41 +1,104 @@
import hglib from "https://esm.sh/[email protected]?deps=react@17,react-dom@17,pixi.js@6";
// import hglib from "https://esm.sh/[email protected]?deps=react@17,react-dom@17,pixi.js@6";
import * as hglib from "http://localhost:5173/app/scripts/hglib.jsx";
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Testing with Vite locally and PR from higlass

@manzt
Copy link
Member Author

manzt commented Feb 16, 2024

Notebooks test code with a widget to collect the Tilesets. A collection of tilesets (should be weakrefable), that handles fulfilling requests from the front end.

import higlass as hg
import ipywidgets
import traitlets
import itertools

class Tilesets(ipywidgets.DOMWidget):
    value = traitlets.Int(0).tag(sync=True)
    def __init__(self):
        super().__init__()
        self.on_msg(self._handle_custom_msg)
        self.ts = dict()

    def add(self, ts):
        self.ts[ts.tileset.uid] = ts.tileset
        return self
        
    def _handle_custom_msg(self, data, buffers):
        payload = data["payload"]
        uuid = data["uuid"]
        match payload:
            case { "type": "tileset_info", "tilesetUid": uid }:
                info = { uid: self.ts[uid].info() }
                self.send({ "uuid": uuid, "payload": info })
            case { "type": "tiles", "tileIds": tids }:
                all_tiles = []
                for uid, tids in itertools.groupby(
                    iterable=sorted(tids), key=lambda tid: tid.split(".")[0]
                ):
                    tiles = self.ts[uid].tiles(list(tids))
                    all_tiles.extend(tiles)
                data = {tid: tval for tid, tval in all_tiles}
                self.send({ "uuid": uuid, "payload": data })
            case _:
                raise ValueError("Something's wrong with the Internet")

ts = hg.cooler("./test.mcool")
tss = Tilesets().add(ts)
track = ts.track("heatmap")
hg.view(track, width=6).widget(ts=tss)

@manzt
Copy link
Member Author

manzt commented Feb 16, 2024

Just other ideas. A tile request "coordinator", that can be shared among tracks. It waits an animation frame to see all the desired tiles, and then dispatches a single server request.

class TileRequestCoordinator {
 #model;
 #requests;
 #frameRequested = false;
 constructor(model) {
   this.#model = model;
   this.#requests = [];
 }
 async fetchTilesetInfo({ tilesetUid }) {
   let { data } = await send(this.#model, { type: "tileset_info", tilesetUid });
   return data;
 }
 async fetchTiles({ tileIds }) {
   if (!this.#frameRequested) {
     this.#frameRequested = true;
     requestAnimationFrame(() => this.#processRequests());
   }
   let { promise, resolve, reject } = Promise.withResolvers();
   this.#requests.push({ tileIds, resolve, reject });
   return promise;
 }
 async #processRequests() {
   this.#frameRequested = false;
   let ids = [...new Set(this.#requests.flatMap((r) => r.tileIds))];
   let { data: resp } = await send(this.#model, { type: "tiles", tileIds: ids });
   let data = tileResponseToData(resp, "jupyter", ids);
   for (let { tileIds, resolve } of this.#requests) {
     let tileData = Object.fromEntries(tileIds.map((id) => [id, data[id]]));
     resolve(tileData);
   }
   this.#requests.length = 0;
 }
 registerTileset() {
   throw new Error("Not implemented");
 }
}

@manzt
Copy link
Member Author

manzt commented Jul 21, 2024

Relevant PR that benefits from a similar kind of architecture (and ability to drop jupyter-server-proxy):

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant