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
WebComponent pane to dramatically speed up creating new widgets in Panel #1122
Conversation
This is amazing. Just for some background for me. Is there some automated way we could generate a set of components for some library including dynamic generation of parameters? For example if the underlying library ships some JSON spec of the components we could use that to auto-generate the components. |
I've added 3 reviewers. Mostly because I think this is very important functionality (Otherwise please tell me why not) and if you have the time to review it a bit to improve and learn it would be so awesome. This is work in progress and will be improved dramatically. I will let you now when it's ready for review. |
As another maybe simpler approach instead of actually generating panel components from some JSON spec it might be nice to at least parse the HTML and make the attributes of the component accessible (and settable?) as a dictionary. |
Yeah the PR is still using the old deprecated approach to building extensions. |
Was wondering if it was on purpose to not incrase size of the bundle |
No, I think @MarcSkovMadsen is still learning how to develop extensions and we still don't have a decent developer guide for it. |
@MarcSkovMadsen |
panel/components/wired/buttons.py
Outdated
import panel as pn | ||
pn.config.sizing_mode="stretch_width" | ||
|
||
js = """ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be nicer to append these urls to pn.config.js_files
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Eventually they should.
If you take a look the value of js
you can see only one of the two imports can be done via pn.config.js_files
. In one of the imports I need to specify the type
.
js = """
<script src="https://unpkg.com/@webcomponents/webcomponentsjs@2.0.0/webcomponents-loader.js"></script>
<script type="module" src="https://unpkg.com/wired-elements@0.6.4/dist/wired-elements.bundled.js"></script>
"""
In general the import of js
web component libraries does not always work for me. It needs some experimentation before it works. Sometimes I need to
- add
type="module"
- add ``?module` to the url.
- add additional javascript libraries than what is described on npm or in the documentation.
(I believe)
So I guess there will be a request to improve the pn.config.js_files
at some stage. At a minimum be able to specify the type
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was wondering about that. Will have to do some reading before making any concrete suggestions.
Thanks for all your comments and improvements above. I have briefly read them but I wan't to comment how I expect to improve/ finalize the WebComponent concept. The overall idea/ goal is to allow the user to inherit from the WebComponent and
I hope this will all work out. The perspective is that it will be much easier to contribute new widgets to Panel
|
One more thing I would like to provide is a js_files =[
{ "src": "https://unpkg.com/wired-elements@0.6.4/dist/wired-elements.bundled.js",
"type"= "module" },
} The user still needs to remember to add them manually |
After the model web_component.py file was modified in bcff9ae I get the error How do I build and register the model before I run Before the the implementation used the I've tried the below without luck $ python -m panel serve 'panel\tests\components\widgets\test_wired.py' --dev --show
2020-02-29 05:18:52,100 Starting Bokeh server version 1.4.0 (running on Tornado 6.0.3)
2020-02-29 05:18:52,100 User authentication hooks NOT provided (default user enabled)
2020-02-29 05:18:52,100 Bokeh app running at: http://localhost:5006/test_wired
2020-02-29 05:18:52,100 Starting Bokeh server with process id: 4368
Compilation failed:
panel/models/web_component.ts:1:38 - error TS2307: Cannot find module '@bokehjs/models/layouts/html_box'.
1 import { HTMLBox, HTMLBoxView } from "@bokehjs/models/layouts/html_box"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
panel/models/web_component.ts:4:20 - error TS2307: Cannot find module '@bokehjs/core/properties'.
4 import * as p from "@bokehjs/core/properties"
~~~~~~~~~~~~~~~~~~~~~~~~~~
panel/models/web_component.ts:16:14 - error TS2339: Property 'connect' does not exist on type 'WebComponentView'.
16 this.connect(this.model.properties.innerHTML.change, () => this.render())
~~~~~~~
panel/models/web_component.ts:22:18 - error TS2339: Property 'el' does not exist on type 'WebComponentView'.
22 if (this.el.innerHTML !== this.model.innerHTML) {
~~
panel/models/web_component.ts:22:46 - error TS2339: Property 'innerHTML' does not exist on type 'WebComponent'.
22 if (this.el.innerHTML !== this.model.innerHTML) {
~~~~~~~~~
panel/models/web_component.ts:23:18 - error TS2339: Property 'el' does not exist on type 'WebComponentView'.
23 this.el.innerHTML = this.model.innerHTML; // Todo: Remove
~~
panel/models/web_component.ts:23:44 - error TS2339: Property 'innerHTML' does not exist on type 'WebComponent'.
23 this.el.innerHTML = this.model.innerHTML; // Todo: Remove
~~~~~~~~~
panel/models/web_component.ts:24:45 - error TS2339: Property 'el' does not exist on type 'WebComponentView'.
24 this.webComponentElement = this.el.firstElementChild;
~~
panel/models/web_component.ts:45:24 - error TS2339: Property 'innerHTML' does not exist on type 'WebComponent'.
45 if (this.model.innerHTML !== this.webComponentElement.outerHTML) {
~~~~~~~~~
panel/models/web_component.ts:46:24 - error TS2339: Property 'innerHTML' does not exist on type 'WebComponent'.
46 this.model.innerHTML = this.webComponentElement.outerHTML;
~~~~~~~~~
panel/models/web_component.ts:70:24 - error TS2339: Property 'default_view' does not exist on type 'WebComponent'.
70 this.prototype.default_view = WebComponentView;
~~~~~~~~~~~~
panel/models/web_component.ts:72:14 - error TS2339: Property 'define' does not exist on type 'typeof WebComponent'.
72 this.define<WebComponent.Props>({
~~~~~~
(.venv)
MASMA@PC70601 MINGW64 /c/repos/private/panel (web_component)
$ bokeh build
Working directory: C:\repos\private\panel
Not a bokeh extension. Quitting.
(.venv)
MASMA@PC70601 MINGW64 /c/repos/private/panel (web_component)
$ panel build
Working directory: C:\repos\private\panel
Not a bokeh extension. Quitting.
(.venv)
MASMA@PC70601 MINGW64 /c/repos/private/panel (web_component)
$ bokeh build "panel\models\web_component.py"
Working directory: C:\repos\private\panel\panel\models\web_component.py
Not a bokeh extension. Quitting. |
Did you compile the models with |
Nope. I forgot that was what I had to do. Now it works. Thanks. |
Added Really easy to support communication from server to client. The other way is not supported (yet). And the data transfer is a simple HTML = """
<div class="echart" style="width:100%;height:100%;"></div>
<script type="text/javascript">
var myScript = document.currentScript;
var myDiv = myScript.parentElement.firstElementChild;
var myChart = echarts.init(myDiv);
myDiv.eChart = myChart;
Object.defineProperty(myDiv, 'option', {
get: function() { return null; },
set: function(val) { this.eChart.setOption(val); this.eChart.resize();}
});
Object.defineProperty(myDiv, 'resizes', {
get: function() { return null; },
set: function(val) { this.eChart.resize();}
});
</script>"""
class EChart(pn.pane.WebComponent):
html = param.String(HTML)
properties_to_watch = param.Dict({"option": "option", "resizes": "resizes"})
echart = param.Parameter()
option = param.Dict()
resizes = param.Integer()
def __init__(self, **params):
if "echart" in params:
params["option"] = self._to_echart_dict(params["echart"])
super().__init__(**params)
@classmethod
def _to_echart_dict(cls, echart):
if isinstance(echart, dict):
return echart
if 'pyecharts' in sys.modules:
import pyecharts
if isinstance(echart, pyecharts.charts.chart.Chart):
return json.loads(echart.dump_options())
return {}
@param.depends("echart", watch=True)
def update(self):
self.option = self._to_echart_dict(self.echart) This only thing I can't get working is @philippjfr or @xavArtley Any idea how to get this working? You can run the example using python -m panel serve 'panel\tests\test_echart.py' --dev --show |
May be like for the vtk panel you have to override after_layout method and call the resize method in it |
Thanks @xavArtley . That did the trick. |
I cannot find |
We've discussed to refactor this pull request into such that
@philippjfr . Could you please confirm this is what you want? (It will require some work on my side, so please confirm). |
Yes, I think this makes the most sense. As we refine the WebComponent model and the examples we can eventually consider migrating them into Panel itself or creating one or more panel extension packages. |
Superseded by #1122 |
In case others stumble across this, it was meant to read "Superseded by #1252" |
I believe I have created a proof of concept for how to use web components in panel to speed up the time to market for creating new widgets.
If you run something like
python -m panel serve 'panel\components\wired\buttons.py' --dev --show
Then you can explore the below
It's not all fully working yet - but the principles have been identified.