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

Support Panel/ Does not work with Panel #62

Closed
MarcSkovMadsen opened this issue Jan 27, 2022 · 23 comments
Closed

Support Panel/ Does not work with Panel #62

MarcSkovMadsen opened this issue Jan 27, 2022 · 23 comments
Labels
enhancement New feature or request

Comments

@MarcSkovMadsen
Copy link

MarcSkovMadsen commented Jan 27, 2022

Hi John

Congrats with VegaFusion.

I just tried it out with Panel. I would expect/ hope it would work as an ipywidget. But it does not.

pip install panel vegafusion-jupyter vega-datasets ipywidgets_bokeh
import panel as pn
import altair as alt
from vega_datasets import data

import vegafusion_jupyter as vf
vf.enable()

pn.extension("ipywidgets", template="fast")

ACCENT = "#1f77b4"
PALETTE = [ACCENT, "#ff7f0e", "#2ca02c", "#d62728", "#9467bd", "#8c564b", "#e377c2", "#7f7f7f", "#bcbd22", "#17becf"]

if not "panel-vegafusion" in pn.state.cache:
    seattle_weather = pn.state.cache["panel-vegafusion"]=data.seattle_weather()
else:
    seattle_weather = pn.state.cache["panel-vegafusion"]

def get_chart(seattle_weather):
    brush = alt.selection(type='interval', encodings=['x'])

    bars = alt.Chart().mark_bar().encode(
        x='month(date):O',
        y='mean(precipitation):Q',
        opacity=alt.condition(brush, alt.OpacityValue(1), alt.OpacityValue(0.7)),
    ).add_selection(
        brush
    )

    line = alt.Chart().mark_rule(color='firebrick').encode(
        y='mean(precipitation):Q',
        size=alt.SizeValue(3)
    ).transform_filter(
        brush
    )

    return alt.layer(bars, line, data=seattle_weather)

chart = get_chart(seattle_weather)

pn.panel(chart).servable()

pn.state.template.param.update(
    site="Vegafusion", title="Interactive Big Data Apps with Crossfiltering",
    accent_base_color=ACCENT, header_background=ACCENT
)
panel serve panel_vegafusion_app.py --static-dirs _vegafusion_data=./_vegafusion_data

image

WARN Loading failed _vegafusion_data/vegafusion-7bd7f9dd903be78e727c1b52e745f4f17d1212dd.feather SyntaxError: Unexpected token A in JSON at position 0
@MarcSkovMadsen MarcSkovMadsen changed the title Does not work with Panel Support Panel/ Does not work with Panel Jan 27, 2022
@jonmmease
Copy link
Collaborator

Thanks for giving it a try @MarcSkovMadsen! I'm not familiar with the internals of how Panel provides support for Jupyter Widgets. But it would definitely be great to either get this working, or to provide a dedicated Panel extension.

@jonmmease jonmmease added the enhancement New feature or request label Jan 27, 2022
@MarcSkovMadsen
Copy link
Author

MarcSkovMadsen commented Jan 28, 2022

A first thought is that Panel probably does not see this as a general Ipywidget but as the Altair widget and just tries to communicate the vega-lite json spec. So next step is to use the VegaFusionWidget.

import panel as pn
import altair as alt
from vega_datasets import data

pn.extension("ipywidgets", template="fast")

from vegafusion_jupyter import VegaFusionWidget

ACCENT = "#1f77b4"
PALETTE = [ACCENT, "#ff7f0e", "#2ca02c", "#d62728", "#9467bd", "#8c564b", "#e377c2", "#7f7f7f", "#bcbd22", "#17becf"]

if not "panel-vegafusion" in pn.state.cache:
    seattle_weather = pn.state.cache["panel-vegafusion"]=data.seattle_weather()
else:
    seattle_weather = pn.state.cache["panel-vegafusion"]

def get_chart(seattle_weather):
    brush = alt.selection(type='interval', encodings=['x'])

    bars = alt.Chart().mark_bar().encode(
        x='month(date):O',
        y='mean(precipitation):Q',
        opacity=alt.condition(brush, alt.OpacityValue(1), alt.OpacityValue(0.7)),
    ).add_selection(
        brush
    )

    line = alt.Chart().mark_rule(color='firebrick').encode(
        y='mean(precipitation):Q',
        size=alt.SizeValue(3)
    ).transform_filter(
        brush
    )

    return alt.layer(bars, line, data=seattle_weather)

chart = get_chart(seattle_weather)
vchart = VegaFusionWidget(chart)
pn.pane.IPyWidget(vchart).servable()

pn.state.template.param.update(
    site="Vegafusion", title="Interactive Big Data Apps with Crossfiltering",
    accent_base_color=ACCENT, header_background=ACCENT
)
$ panel serve 'panel_vegafusion_app.py'
2022-01-28 01:59:38,588 Starting Bokeh server version 2.4.2 (running on Tornado 6.1)
2022-01-28 01:59:38,596 User authentication hooks NOT provided (default user enabled)
2022-01-28 01:59:38,601 Bokeh app running at: http://localhost:5006/panel_vegafusion_app
2022-01-28 01:59:38,602 Starting Bokeh server with process id: 18208

---------SEND--------------
stream <ipywidgets_bokeh.kernel.WebsocketStream object at 0x0000029ABB811820>
msg_type comm_open
content {'data': {'state': {'_model_module': '@jupyter-widgets/base', '_model_module_version': '1.2.0', '_model_name': 'LayoutModel', '_view_count': None, '_view_module': '@jupyter-widgets/base', '_view_module_version': '1.2.0', '_view_name': 'LayoutView', 'align_content': None, 'align_items': None, 'align_self': None, 'border': None, 'bottom': None, 'display': None, 'flex': None, 'flex_flow': None, 'grid_area': None, 'grid_auto_columns': None, 'grid_auto_flow': None, 'grid_auto_rows': None, 'grid_column': None, 'grid_gap': None, 'grid_row': None, 'grid_template_areas': None, 'grid_template_columns': None, 'grid_template_rows': None, 'height': None, 'justify_content': None, 'justify_items': None, 'left': None, 'margin': None, 'max_height': None, 'max_width': None, 'min_height': None, 'min_width': None, 'object_fit': None, 
'object_position': None, 'order': None, 'overflow': None, 'overflow_x': None, 'overflow_y': None, 'padding': None, 'right': None, 'top': None, 'visibility': None, 'width': None}, 'buffer_paths': []}, 'comm_id': 'b6744b8551fd4011b0546411cdaf1ba7', 'target_name': 'jupyter.widget', 'target_module': None}
parent {}
header None
metadata {'version': '2.0.0'}
data {"header": {"msg_id": "e1061adc-4bea603cc82aeb2970e4f28d_18208_0", "msg_type": "comm_open", "username": "username", "session": "e1061adc-4bea603cc82aeb2970e4f28d", "date": "2022-01-28T00:59:45.793502Z", "version": "5.3"}, "msg_id": "e1061adc-4bea603cc82aeb2970e4f28d_18208_0", "msg_type": "comm_open", "parent_header": {}, "content": {"data": {"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}, "buffer_paths": []}, "comm_id": "b6744b8551fd4011b0546411cdaf1ba7", "target_name": "jupyter.widget", "target_module": null}, "metadata": {"version": "2.0.0"}, "channel": "iopub"}       

---------SEND--------------
stream <ipywidgets_bokeh.kernel.WebsocketStream object at 0x0000029ABB811820>
msg_type comm_open
content {'data': {'state': {'_dom_classes': (), '_model_module': 'vegafusion-jupyter', '_model_module_version': '^0.0.2', '_model_name': 'VegaFusionModel', '_view_count': None, '_view_module': 'vegafusion-jupyter', '_view_module_version': '^0.0.2', '_view_name': 'VegaFusionView', 'client_vega_spec': None, 'comm_plan': None, 'debounce_max_wait': 60.0, 'debounce_wait': 30.0, 'download_source_link': None, 'full_vega_spec': None, 'layout': 'IPY_MODEL_b6744b8551fd4011b0546411cdaf1ba7', 'server_vega_spec': None, 'spec': '{\n  "config": {\n    "view": {\n  
    "continuousWidth": 400,\n      "continuousHeight": 300\n    }\n  },\n  "layer": [\n    {\n      "mark": "bar",\n      "encoding": {\n  
      "opacity": {\n          "condition": {\n            "value": 1,\n            "selection": "selector001"\n          },\n          "value": 0.7\n        },\n        "x": {\n          "field": "date",\n          "timeUnit": "month",\n          "type": "ordinal"\n        },\n        "y": {\n          "aggregate": "mean",\n          "field": "precipitation",\n          "type": "quantitative"\n        }\n      },\n      "selection": {\n        "selector001": {\n          "type": "interval",\n          "encodings": [\n            "x"\n          ]\n   
     }\n      }\n    },\n    {\n      "mark": {\n        "type": "rule",\n        "color": "firebrick"\n      },\n      "encoding": {\n    
    "size": {\n          "value": 3\n        },\n        "y": {\n          "aggregate": "mean",\n          "field": "precipitation",\n     
     "type": "quantitative"\n        }\n      },\n      "transform": [\n        {\n          "filter": {\n            "selection": "selector001"\n          }\n        }\n      ]\n    }\n  ],\n  "data": {\n    "url": "_vegafusion_data/vegafusion-7bd7f9dd903be78e727c1b52e745f4f17d1212dd.feather"\n  },\n  "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json"\n}', 'verbose': False}, 'buffer_paths': []}, 'comm_id': '0582b62fd2c64638b4821fd5d8c4040d', 'target_name': 'jupyter.widget', 'target_module': None}
parent {}
header None
metadata {'version': '2.0.0'}
data {"header": {"msg_id": "e1061adc-4bea603cc82aeb2970e4f28d_18208_1", "msg_type": "comm_open", "username": "username", "session": "e1061adc-4bea603cc82aeb2970e4f28d", "date": "2022-01-28T00:59:45.799505Z", "version": "5.3"}, "msg_id": "e1061adc-4bea603cc82aeb2970e4f28d_18208_1", "msg_type": "comm_open", "parent_header": {}, "content": {"data": {"state": {"_dom_classes": [], "_model_module": "vegafusion-jupyter", "_model_module_version": "^0.0.2", "_model_name": "VegaFusionModel", "_view_count": null, "_view_module": "vegafusion-jupyter", "_view_module_version": "^0.0.2", "_view_name": "VegaFusionView", "client_vega_spec": null, "comm_plan": null, "debounce_max_wait": 60.0, "debounce_wait": 30.0, "download_source_link": null, "full_vega_spec": null, "layout": "IPY_MODEL_b6744b8551fd4011b0546411cdaf1ba7", "server_vega_spec": null, "spec": "{\n  \"config\": {\n    \"view\": {\n      \"continuousWidth\": 400,\n      \"continuousHeight\": 300\n    }\n  },\n  \"layer\": [\n    {\n      \"mark\": \"bar\",\n      \"encoding\": {\n        \"opacity\": {\n          \"condition\": {\n            \"value\": 1,\n            \"selection\": \"selector001\"\n          },\n          \"value\": 0.7\n        },\n        \"x\": {\n          \"field\": \"date\",\n          \"timeUnit\": \"month\",\n          \"type\": \"ordinal\"\n        },\n        \"y\": {\n          \"aggregate\": \"mean\",\n          \"field\": \"precipitation\",\n          \"type\": \"quantitative\"\n        }\n      },\n      \"selection\": {\n     
   \"selector001\": {\n          \"type\": \"interval\",\n          \"encodings\": [\n            \"x\"\n          ]\n        }\n      }\n 
   },\n    {\n      \"mark\": {\n        \"type\": \"rule\",\n        \"color\": \"firebrick\"\n      },\n      \"encoding\": {\n        \"size\": {\n          \"value\": 3\n        },\n        \"y\": {\n          \"aggregate\": \"mean\",\n          \"field\": \"precipitation\",\n          \"type\": \"quantitative\"\n        }\n      },\n      \"transform\": [\n        {\n          \"filter\": {\n            \"selection\": \"selector001\"\n          }\n        }\n      ]\n    }\n  ],\n  \"data\": {\n    \"url\": \"_vegafusion_data/vegafusion-7bd7f9dd903be78e727c1b52e745f4f17d1212dd.feather\"\n  },\n  \"$schema\": \"https://vega.github.io/schema/vega-lite/v4.17.0.json\"\n}", "verbose": false}, "buffer_paths": []}, "comm_id": "0582b62fd2c64638b4821fd5d8c4040d", "target_name": "jupyter.widget", "target_module": null}, "metadata": {"version": "2.0.0"}, "channel": "iopub"}
2022-01-28 01:59:46,288 WebSocket connection opened
2022-01-28 01:59:46,289 ServerConnection created

image

594.index.js:1 
        
       panicked at 'send_request function call failed: JsValue(Error: [object ArrayBuffer] is not serializable
Error: [object ArrayBuffer] is not serializable
    at f.to_serializable (http://localhost:5006/static/js/bokeh.min.js?v=b3e0592a1e90448fa40dcddd5cd5217dcd6b3c7dd368020f6a8e4be4fdd1adbdeb2824eb75ab4f5120c80dc7684f8ff2aa2f8b00d6f393108c96d2f6f2cf0297:195:1391)
    at l.[serialize] (http://localhost:5006/static/js/bokeh.min.js?v=b3e0592a1e90448fa40dcddd5cd5217dcd6b3c7dd368020f6a8e4be4fdd1adbdeb2824eb75ab4f5120c80dc7684f8ff2aa2f8b00d6f393108c96d2f6f2cf0297:200:458)
    at f.to_serializable (http://localhost:5006/static/js/bokeh.min.js?v=b3e0592a1e90448fa40dcddd5cd5217dcd6b3c7dd368020f6a8e4be4fdd1adbdeb2824eb75ab4f5120c80dc7684f8ff2aa2f8b00d6f393108c96d2f6f2cf0297:195:1042)
    at f.to_serializable (http://localhost:5006/static/js/bokeh.min.js?v=b3e0592a1e90448fa40dcddd5cd5217dcd6b3c7dd368020f6a8e4be4fdd1adbdeb2824eb75ab4f5120c80dc7684f8ff2aa2f8b00d6f393108c96d2f6f2cf0297:195:1169)
    at E.create_json_patch (http://localhost:5006/static/js/bokeh.min.js?v=b3e0592a1e90448fa40dcddd5cd5217dcd6b3c7dd368020f6a8e4be4fdd1adbdeb2824eb75ab4f5120c80dc7684f8ff2aa2f8b00d6f393108c96d2f6f2cf0297:165:9308)
    at r._document_changed (http://localhost:5006/static/js/bokeh.min.js?v=b3e0592a1e90448fa40dcddd5cd5217dcd6b3c7dd368020f6a8e4be4fdd1adbdeb2824eb75ab4f5120c80dc7684f8ff2aa2f8b00d6f393108c96d2f6f2cf0297:590:850)
    at _document_listener (http://localhost:5006/static/js/bokeh.min.js?v=b3e0592a1e90448fa40dcddd5cd5217dcd6b3c7dd368020f6a8e4be4fdd1adbdeb2824eb75ab4f5120c80dc7684f8ff2aa2f8b00d6f393108c96d2f6f2cf0297:590:162)
    at E._trigger_on_change (http://localhost:5006/static/js/bokeh.min.js?v=b3e0592a1e90448fa40dcddd5cd5217dcd6b3c7dd368020f6a8e4be4fdd1adbdeb2824eb75ab4f5120c80dc7684f8ff2aa2f8b00d6f393108c96d2f6f2cf0297:165:4698)
    at gg.bk_send (http://localhost:5006/static/extensions/ipywidgets_bokeh/ipywidgets_bokeh.js?v=206620a657f1ccc8af72b866fdcef20e641c48f39ce27f338ce8313949c63e53:2:2745297)
    at e.send (http://localhost:5006/static/extensions/ipywidgets_bokeh/ipywidgets_bokeh.js?v=206620a657f1ccc8af72b866fdcef20e641c48f39ce27f338ce8313949c63e53:2:2743285))', vegafusion-wasm/src/lib.rs:330:14

Stack:

Error
    at Object.G (https://unpkg.com/[email protected]/dist/594.index.js:1:7607)
    at __wbg_new_693216e109162396 (https://unpkg.com/vegafusion-jupyter@%5E0.0.2/dist/index.js:1:22417)
    at https://unpkg.com/[email protected]/dist/d0048f4ff7544ce1ea76.module.wasm:wasm-function[2561]:0x3d8a32
    at https://unpkg.com/[email protected]/dist/d0048f4ff7544ce1ea76.module.wasm:wasm-function[5005]:0x4491e5
    at https://unpkg.com/[email protected]/dist/d0048f4ff7544ce1ea76.module.wasm:wasm-function[3646]:0x42ed5b
    at https://unpkg.com/[email protected]/dist/d0048f4ff7544ce1ea76.module.wasm:wasm-function[3935]:0x43bbbf
    at https://unpkg.com/[email protected]/dist/d0048f4ff7544ce1ea76.module.wasm:wasm-function[4371]:0x445b30
    at https://unpkg.com/[email protected]/dist/d0048f4ff7544ce1ea76.module.wasm:wasm-function[4417]:0x4463d7
    at https://unpkg.com/[email protected]/dist/d0048f4ff7544ce1ea76.module.wasm:wasm-function[3974]:0x43ceec
    at https://unpkg.com/[email protected]/dist/d0048f4ff7544ce1ea76.module.wasm:wasm-function[1422]:0x33ce35


nn @ 594.index.js:1
ipywidgets_bokeh.js?v=206620a657f1ccc8af72b866fdcef20e641c48f39ce27f338ce8313949c63e53:2 
        
       Error: Could not create a view for model id 0582b62fd2c64638b4821fd5d8c4040d
    at ipywidgets_bokeh.js?v=206620a657f1ccc8af72b866fdcef20e641c48f39ce27f338ce8313949c63e53:2:2087124
(anonymous) @ ipywidgets_bokeh.js?v=206620a657f1ccc8af72b866fdcef20e641c48f39ce27f338ce8313949c63e53:2
ipywidgets_bokeh.js?v=206620a657f1ccc8af72b866fdcef20e641c48f39ce27f338ce8313949c63e53:2 
        
       Error: Could not create view
    at ipywidgets_bokeh.js?v=206620a657f1ccc8af72b866fdcef20e641c48f39ce27f338ce8313949c63e53:2:2087124
    at async gg.render (ipywidgets_bokeh.js?v=206620a657f1ccc8af72b866fdcef20e641c48f39ce27f338ce8313949c63e53:2:2744026)
    at async _g._render (ipywidgets_bokeh.js?v=206620a657f1ccc8af72b866fdcef20e641c48f39ce27f338ce8313949c63e53:2:2744950)
(anonymous) @ ipywidgets_bokeh.js?v=206620a657f1ccc8af72b866fdcef20e641c48f39ce27f338ce8313949c63e53:2
2d0048f4ff7544ce1ea76.module.wasm:0x42ed91 
        
       Uncaught (in promise) RuntimeError: unreachable
    at d0048f4ff7544ce1ea76.module.wasm:0x42ed91
    at d0048f4ff7544ce1ea76.module.wasm:0x43bbbf
    at d0048f4ff7544ce1ea76.module.wasm:0x445b30
    at d0048f4ff7544ce1ea76.module.wasm:0x4463d7
    at d0048f4ff7544ce1ea76.module.wasm:0x43ceec
    at d0048f4ff7544ce1ea76.module.wasm:0x33ce35
    at d0048f4ff7544ce1ea76.module.wasm:0x1714ab
    at d0048f4ff7544ce1ea76.module.wasm:0x43abec
    at d.J [as render_vegafusion] (594.index.js:1:4972)
    at d.value_changed (index.js:1:14547)

@MarcSkovMadsen
Copy link
Author

MarcSkovMadsen commented Jan 28, 2022

My guess is that ipywidgets_bokeh/ 'bokeh' package does not support communication anything non-serializable? I reported the issue here bokeh/ipywidgets_bokeh#46

So I figured we probably need a custom Panel component. I'm exploring here https://github.com/MarcSkovMadsen/panel-vegafusion

@jonmmease
Copy link
Collaborator

I think the issue may be related to this line

https://github.com/vegafusion/vegafusion/blob/4f261d0aea9eaf1c220de29c5f396d95025e4af2/python/vegafusion-jupyter/src/widget.ts#L242

The second argument to send as an array of binary ArrayBuffers. Jupyter Widgets serializes these as binary (not JSON). The issue may be similar to what I ran into with Colab (#55).

For better ecosystem support, it might be better to get rid of the use of send and instead pass data between client and server by assigning to dedicated Traitlet properties. This is what I did for the plotly FigureWidget which works at least in Colab.

@MarcSkovMadsen
Copy link
Author

MarcSkovMadsen commented Jan 28, 2022

Do you now if the current way of communication is "official", "standard" Ipywidget communication? I.e. is it "fair" to require ipywidgets_bokeh to be able to handle that kind of communication.

@jonmmease
Copy link
Collaborator

Do you now if the current way of communication is "official",

I think so. send here is a method on the WidgetModel class.

https://github.com/jupyter-widgets/ipywidgets/blob/64560324517844485a3c31e4dbb5e0550327a369/packages/base/src/widget.ts#L163-L175

@MarcSkovMadsen
Copy link
Author

I put in a License disclaimer in my repository. Please let me know if there are any issues due to my lack of understanding. I don't want to do anything wrong here. Thanks.

image

https://github.com/MarcSkovMadsen/panel-vegafusion

@jonmmease
Copy link
Collaborator

Hi @MarcSkovMadsen. There's definitely no issue creating a repo that uses VegaFusion this way. Technically, I think panel-vegafusion would itself need to be licensed under the AGPL once it is being distributed to people. One note is that currently the drop-down menu with the "Download Source" link logic is done in JavaScript in VegaFusionWidget, but I'm planning to move that into the vegafusion-wasm dependency so that it can be shared across other extensions.

@MarcSkovMadsen
Copy link
Author

MarcSkovMadsen commented Jan 28, 2022

Yes. As I work my way through this I can see some things that probably needs to change in order for the project to easily integrate into Panel, Dash, Streamlit etc.

Right now I mainly lack the .js files to build the component on top of. I am not very strong in the Rust and .js tool chain. So having easy access to the vegafusion-wasm file(s) either locally on my laptop, via npm or in the github repository would make things so much easier for me. And if I go with a Panel ReactiveHTML implementation there would be no .js build step. There could be if I made a Bokeh extension. Its just so much easier to first make the extension in ReactiveHTML.

Could you share the working vegafusion-wasm file(s) somehow?

@jonmmease
Copy link
Collaborator

vegafusion-wasm is published to npm: https://www.npmjs.com/package/vegafusion-wasm. In includes JavaScript/TypeScript bindings, so hopefully could could treat it as a regular dependency.

@MarcSkovMadsen
Copy link
Author

Ok. I would really be using unkpg. But if I go to https://unpkg.com/vegafusion-wasm I see

image

@MarcSkovMadsen
Copy link
Author

But https://unpkg.com/browse/vegafusion-wasm/ seems to give something

image

@MarcSkovMadsen
Copy link
Author

MarcSkovMadsen commented Jan 28, 2022

If I can get something along the lines of

<script type="module" src="https://unpkg.com/[email protected]">
console.log("working!")
</script>

then I would be flying I believe. Will have to experiment.

@MarcSkovMadsen
Copy link
Author

Ok. will try implementing a Bokeh Extension and using .js build tools.

@MarcSkovMadsen
Copy link
Author

MarcSkovMadsen commented Jan 29, 2022

Ok. Next problem. bokeh build does not support linking .wasm files.

I've reached out on the Bokeh Discourse https://discourse.bokeh.org/t/how-do-i-build-bokeh-extension-with-wasm-depencency/8842.

The current branch can be explored via https://github.com/MarcSkovMadsen/panel-vegafusion/tree/0e4f5ab63d4b4231515449442e497cb8e3bf535d.

Exception

jovyan@jupyter-marcskovmadsen-2dpanel-2dvegafusion-2d7y6mmeo2:~/src/panel_vegafusion$ bokeh build
Working directory: /home/jovyan/src/panel_vegafusion
New development environment. Running npm install.
npm WARN read-shrinkwrap This version of npm is compatible with lockfileVersion@1, but package-lock.json was generated for lockfileVersion@2. I'll try to do my best with it!
npm WARN [email protected] No description

added 122 packages from 94 contributors and audited 122 packages in 18.04s

4 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

Using /home/jovyan/src/panel_vegafusion/tsconfig.json
Compiling styles
Compiling TypeScript (3 files)
Linking modules
Error: unsupported extension of /home/jovyan/src/panel_vegafusion/node_modules/vegafusion-wasm/vegafusion_wasm_bg.wasm
    at /srv/conda/envs/notebook/lib/python3.7/site-packages/bokeh/server/static/js/compiler.js:170912:31
    at Linker.new_module (/srv/conda/envs/notebook/lib/python3.7/site-packages/bokeh/server/static/js/compiler.js:170914:15)
    at Linker.resolve (/srv/conda/envs/notebook/lib/python3.7/site-packages/bokeh/server/static/js/compiler.js:171055:37)
    at Linker.link (/srv/conda/envs/notebook/lib/python3.7/site-packages/bokeh/server/static/js/compiler.js:170637:36)
    at build (/srv/conda/envs/notebook/lib/python3.7/site-packages/bokeh/server/static/js/compiler.js:169312:50)
    at processTicksAndRejections (internal/process/task_queues.js:95:5)
    at async main (/srv/conda/envs/notebook/lib/python3.7/site-packages/bokeh/server/static/js/compiler.js:203:32)

Reproduce on Binder

image

@MarcSkovMadsen
Copy link
Author

MarcSkovMadsen commented Jan 30, 2022

Ok. Now have something working that just needs a bit of polish.

panel-vegafusion-dev-test.mp4

@jonmmease
Copy link
Collaborator

nice! Did you end up needing #63? I'd say don't worry about the re-implementing the dropdown menu for now (unless you already have) since I'm planning to move that logic into the WebAssembly layer.

@MarcSkovMadsen
Copy link
Author

MarcSkovMadsen commented Jan 30, 2022

I did not get to trying #63 yet. But I hope to. Instead I got inspired by the vegafusion-jupyter npm/ webpack build configuration and ended up getting something working. Wow that was tough.

The codesandbox code I also got working did not build when exported and build locally. Parcel does seem to have difficulties building packages with wasm dependencies.

@MarcSkovMadsen
Copy link
Author

I will close this one and make more specific issues and features requests on the back of this.

I think this one got long and messy. But hope other component builders might find something useful here one day.

@MarcSkovMadsen
Copy link
Author

MarcSkovMadsen commented Jan 30, 2022

Regarding the drop down menu. My initial thought was that it should be carved out from vegafusion-jupyter. But it was actually nice that to just use the inspiration and be able to add my own menu-items.

You can find the implementation here if you are interested.

https://github.com/MarcSkovMadsen/panel-vegafusion/blob/main/src/panel_vegafusion/vegafusion_pane.py

I ended up using a Panel ReactiveHTML implementation. The development process is just much smoother than a Bokeh Extension. But there are pros of a Bokeh Extension. So might convert to that one day. Currently the basics of a Bokeh implementation is in the repo. But I think I will remove it again to simplify the repo.

@jonmmease
Copy link
Collaborator

That's great you were able to get it working as a ReactiveHTML extension. Which files other than vegafusion_pane.py are relevant to the ReactiveHTML version? I'm still not clear on with how you ended up solving the issues around compiling the vegafusion-wasm package.

@MarcSkovMadsen
Copy link
Author

MarcSkovMadsen commented Jan 30, 2022

I build a js library here https://github.com/MarcSkovMadsen/panel-vegafusion/tree/main/src-js

image

It's really just this file. But it takes so much boiler plate to build it.

image

It would make my life so much easier if those two functions render_vegafusion and compile where available in a publicly available .js lib where they could be accessed in the global scope. When I get the energy I will file a FR or PR for that. Believe it will make life so much easier for component developers.

@MarcSkovMadsen
Copy link
Author

MarcSkovMadsen commented Jan 30, 2022

My hypothesis is that building using webpack and the config below where essential. I could not use parcel and when I google about Parcel and wasm what I read makes me wonder if its supported at all.

image

But it is a bit of a hazzle that the build outputs in chunks and the chunks needs to be loaded from a specific publicPath(dist below). I tried to avoid the chunks but could not. I believe I can specify a better publicPath that will enable Panel to just serving without having to resort to ask users to serve them them selves by adding extra flags to the panel serve command as below.

panel serve 'tests/apps/test_dev_app.py' --autoreload --show --static dist=./src-js/dist

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

No branches or pull requests

2 participants