Last active
          December 4, 2024 22:28 
        
      - 
      
 - 
        
Save manzt/5c5e3de6d2cea65d2bb68af03db88249 to your computer and use it in GitHub Desktop.  
    anywidget-arrow.ipynb
  
        
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | { | |
| "cells": [ | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "id": "view-in-github", | |
| "colab_type": "text" | |
| }, | |
| "source": [ | |
| "<a href=\"https://colab.research.google.com/gist/manzt/5c5e3de6d2cea65d2bb68af03db88249/anywidget-arrow.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 1, | |
| "id": "187f0e02-b9db-43a8-b211-379b96e5f1b9", | |
| "metadata": { | |
| "tags": [], | |
| "colab": { | |
| "base_uri": "https://localhost:8080/" | |
| }, | |
| "id": "187f0e02-b9db-43a8-b211-379b96e5f1b9", | |
| "outputId": "47917e5c-99ec-411b-cbd0-f8beb8d468f8" | |
| }, | |
| "outputs": [ | |
| { | |
| "output_type": "stream", | |
| "name": "stdout", | |
| "text": [ | |
| "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.6/1.6 MB\u001b[0m \u001b[31m22.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", | |
| "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m63.2/63.2 kB\u001b[0m \u001b[31m3.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", | |
| "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.0/2.0 MB\u001b[0m \u001b[31m19.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", | |
| "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.6/1.6 MB\u001b[0m \u001b[31m21.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", | |
| "\u001b[?25h" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "# Uncomment below if in Colab\n", | |
| "! pip install --quiet anywidget pandas pyarrow fastparquet duckdb" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 2, | |
| "id": "0c1e3433-02ef-4ca2-b57c-fca8b355bfd6", | |
| "metadata": { | |
| "tags": [], | |
| "colab": { | |
| "base_uri": "https://localhost:8080/" | |
| }, | |
| "id": "0c1e3433-02ef-4ca2-b57c-fca8b355bfd6", | |
| "outputId": "f5cf976e-fcd7-4944-a7c1-ec1259118a63" | |
| }, | |
| "outputs": [ | |
| { | |
| "output_type": "stream", | |
| "name": "stdout", | |
| "text": [ | |
| "--2023-04-25 22:09:29-- https://raw.githubusercontent.com/vega/vega-datasets/main/data/population.json\n", | |
| "Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.108.133, 185.199.109.133, 185.199.110.133, ...\n", | |
| "Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.108.133|:443... connected.\n", | |
| "HTTP request sent, awaiting response... 200 OK\n", | |
| "Length: 27665 (27K) [text/plain]\n", | |
| "Saving to: ‘population.json’\n", | |
| "\n", | |
| "\rpopulation.json 0%[ ] 0 --.-KB/s \rpopulation.json 100%[===================>] 27.02K --.-KB/s in 0s \n", | |
| "\n", | |
| "2023-04-25 22:09:29 (71.4 MB/s) - ‘population.json’ saved [27665/27665]\n", | |
| "\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "!wget https://raw.githubusercontent.com/vega/vega-datasets/main/data/population.json" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "id": "9f4bce7e-a279-4bbb-81b9-7a899b1490e2", | |
| "metadata": { | |
| "tags": [], | |
| "id": "9f4bce7e-a279-4bbb-81b9-7a899b1490e2" | |
| }, | |
| "source": [ | |
| "## IPC with traitlets" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 3, | |
| "id": "b318a902-5794-4d86-b558-a58bfe706295", | |
| "metadata": { | |
| "tags": [], | |
| "colab": { | |
| "base_uri": "https://localhost:8080/", | |
| "height": 91, | |
| "referenced_widgets": [ | |
| "7d5d84ba48af429e86fe029736adafcc", | |
| "f9219907b86849c79e7734e129e2e69b" | |
| ] | |
| }, | |
| "id": "b318a902-5794-4d86-b558-a58bfe706295", | |
| "outputId": "ab54f77f-5d98-46cc-9cc9-67fefed9c0eb" | |
| }, | |
| "outputs": [ | |
| { | |
| "output_type": "display_data", | |
| "data": { | |
| "text/plain": [ | |
| "TraitsExample()" | |
| ], | |
| "application/vnd.jupyter.widget-view+json": { | |
| "version_major": 2, | |
| "version_minor": 0, | |
| "model_id": "7d5d84ba48af429e86fe029736adafcc" | |
| } | |
| }, | |
| "metadata": { | |
| "application/vnd.jupyter.widget-view+json": { | |
| "colab": { | |
| "custom_widget_manager": { | |
| "url": "https://ssl.gstatic.com/colaboratory-static/widgets/colab-cdn-widget-manager/b3e629b1971e1542/manager.min.js" | |
| } | |
| } | |
| } | |
| } | |
| } | |
| ], | |
| "source": [ | |
| "import pathlib\n", | |
| "\n", | |
| "import pandas as pd\n", | |
| "import pyarrow as pa\n", | |
| "\n", | |
| "import anywidget\n", | |
| "import traitlets\n", | |
| "\n", | |
| "\n", | |
| "class TraitsExample(anywidget.AnyWidget):\n", | |
| " _esm = \"\"\"\n", | |
| " import * as arrow from \"https://cdn.jsdelivr.net/npm/apache-arrow@11/+esm\";\n", | |
| " import * as Inputs from \"https://cdn.jsdelivr.net/npm/@observablehq/inputs/+esm\";\n", | |
| "\n", | |
| " export function render(view) {\n", | |
| " view.model.on(\"change:_ipc\", () => {\n", | |
| " let table = arrow.tableFromIPC(view.model.get(\"_ipc\").buffer);\n", | |
| " let el = Inputs.table(table);\n", | |
| " if (view.el.firstChild) {\n", | |
| " view.el.firstChild.replaceWith(el);\n", | |
| " } else {\n", | |
| " view.el.appendChild(el);\n", | |
| " }\n", | |
| " });\n", | |
| " let ipc = view.model.get(\"_ipc\");\n", | |
| " if (!ipc) return;\n", | |
| " let table = arrow.tableFromIPC(ipc.buffer);\n", | |
| " view.el.appendChild(Inputs.table(table));\n", | |
| " }\n", | |
| " \"\"\"\n", | |
| " _ipc = traitlets.Bytes().tag(sync=True)\n", | |
| " df = traitlets.Any()\n", | |
| " \n", | |
| " @traitlets.observe(\"df\")\n", | |
| " def change(self, change):\n", | |
| " table = pa.Table.from_pandas(change.new)\n", | |
| " sink = pa.BufferOutputStream()\n", | |
| " with pa.ipc.new_stream(sink, table.schema) as writer:\n", | |
| " writer.write(table)\n", | |
| " buf = sink.getvalue()\n", | |
| " self._ipc = buf.to_pybytes()\n", | |
| "\n", | |
| " \n", | |
| "df = pd.read_json('./population.json')\n", | |
| "w = TraitsExample(df=df)\n", | |
| "w" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 4, | |
| "id": "5eabc7d0-6a9a-411e-83a7-8465fe3b2134", | |
| "metadata": { | |
| "id": "5eabc7d0-6a9a-411e-83a7-8465fe3b2134" | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "# the df property is \"reactive\", and assignment triggers the \n", | |
| "# 'change:_ipc' event handler in the frontend\n", | |
| "w.df = df.iloc[0:2]" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "id": "9d643579-bdd4-4724-8dea-3ad893dcb055", | |
| "metadata": { | |
| "id": "9d643579-bdd4-4724-8dea-3ad893dcb055" | |
| }, | |
| "source": [ | |
| "## IPC with custom messages" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 5, | |
| "id": "f509d423-8986-46b3-9814-619bb531d8d8", | |
| "metadata": { | |
| "colab": { | |
| "base_uri": "https://localhost:8080/", | |
| "height": 625, | |
| "referenced_widgets": [ | |
| "5ff885222cb049129189c5eed522511b", | |
| "21ea4bf92cda49efbada22e2216a5927" | |
| ] | |
| }, | |
| "id": "f509d423-8986-46b3-9814-619bb531d8d8", | |
| "outputId": "b7594092-e3f9-42c6-a072-f69d2b8d851c" | |
| }, | |
| "outputs": [ | |
| { | |
| "output_type": "display_data", | |
| "data": { | |
| "text/plain": [ | |
| "DuckDB()" | |
| ], | |
| "application/vnd.jupyter.widget-view+json": { | |
| "version_major": 2, | |
| "version_minor": 0, | |
| "model_id": "5ff885222cb049129189c5eed522511b" | |
| } | |
| }, | |
| "metadata": { | |
| "application/vnd.jupyter.widget-view+json": { | |
| "colab": { | |
| "custom_widget_manager": { | |
| "url": "https://ssl.gstatic.com/colaboratory-static/widgets/colab-cdn-widget-manager/b3e629b1971e1542/manager.min.js" | |
| } | |
| } | |
| } | |
| } | |
| } | |
| ], | |
| "source": [ | |
| "import duckdb\n", | |
| "\n", | |
| "class DuckDB(anywidget.AnyWidget):\n", | |
| " _esm = \"\"\"\n", | |
| " import * as arrow from \"https://cdn.jsdelivr.net/npm/apache-arrow@11/+esm\";\n", | |
| " import * as Inputs from \"https://cdn.jsdelivr.net/npm/@observablehq/inputs/+esm\";\n", | |
| " \n", | |
| " function send(query, view, { timeout = 3000 } = {}) {\n", | |
| " let uuid = globalThis.crypto.randomUUID();\n", | |
| " return new Promise((resolve, reject) => {\n", | |
| " let timer = setTimeout(() => {\n", | |
| " reject(new Error(`Promise timed out after ${timeout} ms`));\n", | |
| " view.model.off(\"msg:custom\", handler);\n", | |
| " }, timeout);\n", | |
| " function handler(msg, buffers) {\n", | |
| " if (!(msg.uuid === uuid)) return;\n", | |
| " clearTimeout(timer)\n", | |
| " resolve(buffers[0].buffer);\n", | |
| " view.model.off(\"msg:custom\", handler);\n", | |
| " }\n", | |
| " view.model.on(\"msg:custom\", handler)\n", | |
| " view.model.send({ query, uuid });\n", | |
| " })\n", | |
| " }\n", | |
| "\n", | |
| " export function render(view) {\n", | |
| " let textarea = Object.assign(document.createElement(\"textarea\"), {\n", | |
| " value: `SELECT * from \"population.json\"\\n WHERE sex == 1`,\n", | |
| " });\n", | |
| " textarea.style.width = \"300px\";\n", | |
| " let button = Object.assign(document.createElement(\"button\"), {\n", | |
| " innerText: \"submit\",\n", | |
| " })\n", | |
| " let table_el;\n", | |
| " button.addEventListener(\"click\", async () => {\n", | |
| " let buffer = await send(textarea.value, view);\n", | |
| " let table = arrow.tableFromIPC(buffer);\n", | |
| " if (table_el) table_el.remove();\n", | |
| " table_el = Inputs.table(table);\n", | |
| " view.el.appendChild(table_el);\n", | |
| " });\n", | |
| " view.el.appendChild(textarea);\n", | |
| " view.el.appendChild(button);\n", | |
| " }\n", | |
| " \"\"\"\n", | |
| " \n", | |
| " def __init__(self, *args, **kwargs):\n", | |
| " super().__init__(*args, **kwargs)\n", | |
| " self.on_msg(self._handle_custom_msg)\n", | |
| "\n", | |
| " def _handle_custom_msg(self, msg: dict, buffers: list):\n", | |
| " table = duckdb.sql(msg[\"query\"]).arrow()\n", | |
| " sink = pa.BufferOutputStream()\n", | |
| " with pa.ipc.new_stream(sink, table.schema) as writer:\n", | |
| " writer.write(table) \n", | |
| " self.send({ \"uuid\": msg[\"uuid\"] }, [sink.getvalue().to_pybytes()]) \n", | |
| " \n", | |
| "w = DuckDB()\n", | |
| "w" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "id": "94119aca-e4b0-417e-9b63-d079ee39c1f2", | |
| "metadata": { | |
| "id": "94119aca-e4b0-417e-9b63-d079ee39c1f2" | |
| }, | |
| "outputs": [], | |
| "source": [] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "id": "d0370115-a5ae-4609-84de-7015fcbcdc04", | |
| "metadata": { | |
| "id": "d0370115-a5ae-4609-84de-7015fcbcdc04" | |
| }, | |
| "outputs": [], | |
| "source": [] | |
| } | |
| ], | |
| "metadata": { | |
| "kernelspec": { | |
| "display_name": "Python 3 (ipykernel)", | |
| "language": "python", | |
| "name": "python3" | |
| }, | |
| "language_info": { | |
| "codemirror_mode": { | |
| "name": "ipython", | |
| "version": 3 | |
| }, | |
| "file_extension": ".py", | |
| "mimetype": "text/x-python", | |
| "name": "python", | |
| "nbconvert_exporter": "python", | |
| "pygments_lexer": "ipython3", | |
| "version": "3.10.9" | |
| }, | |
| "colab": { | |
| "provenance": [], | |
| "include_colab_link": true | |
| }, | |
| "widgets": { | |
| "application/vnd.jupyter.widget-state+json": { | |
| "7d5d84ba48af429e86fe029736adafcc": { | |
| "model_module": "anywidget", | |
| "model_name": "AnyModel", | |
| "model_module_version": "0.2.3", | |
| "state": { | |
| "_dom_classes": [], | |
| "_model_module": "anywidget", | |
| "_model_module_version": "0.2.3", | |
| "_model_name": "AnyModel", | |
| "_view_count": null, | |
| "_view_module": "anywidget", | |
| "_view_module_version": "0.2.3", | |
| "_view_name": "AnyView", | |
| "layout": "IPY_MODEL_f9219907b86849c79e7734e129e2e69b", | |
| "_esm": "\n import * as arrow from \"https://cdn.jsdelivr.net/npm/apache-arrow@11/+esm\";\n import * as Inputs from \"https://cdn.jsdelivr.net/npm/@observablehq/inputs/+esm\";\n\n export function render(view) {\n view.model.on(\"change:_ipc\", () => {\n let table = arrow.tableFromIPC(view.model.get(\"_ipc\").buffer);\n let el = Inputs.table(table);\n if (view.el.firstChild) {\n view.el.firstChild.replaceWith(el);\n } else {\n view.el.appendChild(el);\n }\n });\n let ipc = view.model.get(\"_ipc\");\n if (!ipc) return;\n let table = arrow.tableFromIPC(ipc.buffer);\n view.el.appendChild(Inputs.table(table));\n }\n ", | |
| "_anywidget_id": "__main__.TraitsExample" | |
| } | |
| }, | |
| "f9219907b86849c79e7734e129e2e69b": { | |
| "model_module": "@jupyter-widgets/base", | |
| "model_name": "LayoutModel", | |
| "model_module_version": "1.2.0", | |
| "state": { | |
| "_model_module": "@jupyter-widgets/base", | |
| "_model_module_version": "1.2.0", | |
| "_model_name": "LayoutModel", | |
| "_view_count": null, | |
| "_view_module": "@jupyter-widgets/base", | |
| "_view_module_version": "1.2.0", | |
| "_view_name": "LayoutView", | |
| "align_content": null, | |
| "align_items": null, | |
| "align_self": null, | |
| "border": null, | |
| "bottom": null, | |
| "display": null, | |
| "flex": null, | |
| "flex_flow": null, | |
| "grid_area": null, | |
| "grid_auto_columns": null, | |
| "grid_auto_flow": null, | |
| "grid_auto_rows": null, | |
| "grid_column": null, | |
| "grid_gap": null, | |
| "grid_row": null, | |
| "grid_template_areas": null, | |
| "grid_template_columns": null, | |
| "grid_template_rows": null, | |
| "height": null, | |
| "justify_content": null, | |
| "justify_items": null, | |
| "left": null, | |
| "margin": null, | |
| "max_height": null, | |
| "max_width": null, | |
| "min_height": null, | |
| "min_width": null, | |
| "object_fit": null, | |
| "object_position": null, | |
| "order": null, | |
| "overflow": null, | |
| "overflow_x": null, | |
| "overflow_y": null, | |
| "padding": null, | |
| "right": null, | |
| "top": null, | |
| "visibility": null, | |
| "width": null | |
| } | |
| }, | |
| "5ff885222cb049129189c5eed522511b": { | |
| "model_module": "anywidget", | |
| "model_name": "AnyModel", | |
| "model_module_version": "0.2.3", | |
| "state": { | |
| "_dom_classes": [], | |
| "_model_module": "anywidget", | |
| "_model_module_version": "0.2.3", | |
| "_model_name": "AnyModel", | |
| "_view_count": null, | |
| "_view_module": "anywidget", | |
| "_view_module_version": "0.2.3", | |
| "_view_name": "AnyView", | |
| "layout": "IPY_MODEL_21ea4bf92cda49efbada22e2216a5927", | |
| "_esm": "\n import * as arrow from \"https://cdn.jsdelivr.net/npm/apache-arrow@11/+esm\";\n import * as Inputs from \"https://cdn.jsdelivr.net/npm/@observablehq/inputs/+esm\";\n \n function send(query, view, { timeout = 3000 } = {}) {\n let uuid = globalThis.crypto.randomUUID();\n return new Promise((resolve, reject) => {\n let timer = setTimeout(() => {\n reject(new Error(`Promise timed out after ${timeout} ms`));\n view.model.off(\"msg:custom\", handler);\n }, timeout);\n function handler(msg, buffers) {\n if (!(msg.uuid === uuid)) return;\n clearTimeout(timer)\n resolve(buffers[0].buffer);\n view.model.off(\"msg:custom\", handler);\n }\n view.model.on(\"msg:custom\", handler)\n view.model.send({ query, uuid });\n })\n }\n\n export function render(view) {\n let textarea = Object.assign(document.createElement(\"textarea\"), {\n value: `SELECT * from \"population.json\"\n WHERE sex == 1`,\n });\n textarea.style.width = \"300px\";\n let button = Object.assign(document.createElement(\"button\"), {\n innerText: \"submit\",\n })\n let table_el;\n button.addEventListener(\"click\", async () => {\n let buffer = await send(textarea.value, view);\n let table = arrow.tableFromIPC(buffer);\n if (table_el) table_el.remove();\n table_el = Inputs.table(table);\n view.el.appendChild(table_el);\n });\n view.el.appendChild(textarea);\n view.el.appendChild(button);\n }\n ", | |
| "_anywidget_id": "__main__.DuckDB" | |
| } | |
| }, | |
| "21ea4bf92cda49efbada22e2216a5927": { | |
| "model_module": "@jupyter-widgets/base", | |
| "model_name": "LayoutModel", | |
| "model_module_version": "1.2.0", | |
| "state": { | |
| "_model_module": "@jupyter-widgets/base", | |
| "_model_module_version": "1.2.0", | |
| "_model_name": "LayoutModel", | |
| "_view_count": null, | |
| "_view_module": "@jupyter-widgets/base", | |
| "_view_module_version": "1.2.0", | |
| "_view_name": "LayoutView", | |
| "align_content": null, | |
| "align_items": null, | |
| "align_self": null, | |
| "border": null, | |
| "bottom": null, | |
| "display": null, | |
| "flex": null, | |
| "flex_flow": null, | |
| "grid_area": null, | |
| "grid_auto_columns": null, | |
| "grid_auto_flow": null, | |
| "grid_auto_rows": null, | |
| "grid_column": null, | |
| "grid_gap": null, | |
| "grid_row": null, | |
| "grid_template_areas": null, | |
| "grid_template_columns": null, | |
| "grid_template_rows": null, | |
| "height": null, | |
| "justify_content": null, | |
| "justify_items": null, | |
| "left": null, | |
| "margin": null, | |
| "max_height": null, | |
| "max_width": null, | |
| "min_height": null, | |
| "min_width": null, | |
| "object_fit": null, | |
| "object_position": null, | |
| "order": null, | |
| "overflow": null, | |
| "overflow_x": null, | |
| "overflow_y": null, | |
| "padding": null, | |
| "right": null, | |
| "top": null, | |
| "visibility": null, | |
| "width": null | |
| } | |
| } | |
| } | |
| } | |
| }, | |
| "nbformat": 4, | |
| "nbformat_minor": 5 | |
| } | 
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment