Upgrade to Pro — share decks privately, control downloads, hide ads and more …

モダンWebフロントエンド環境で作る
Jupyter Widget

モダンWebフロントエンド環境で作る
Jupyter Widget

PyData Osaka Meetup #3での発表資料です。

Yosuke Onoue

January 21, 2017
Tweet

More Decks by Yosuke Onoue

Other Decks in Technology

Transcript

  1. ⾃自⼰己紹介 • おのうえ (@_likr) • 京都⼤大学 学際融合教育研究推進センター
 政策のための科学ユニット 特定助教 •

    ng-kyotoオーガナイザー、GDG神戸スタッフ
 関⻄西フロントエンドUG、Kobe.py • 可視化、最適化、アルゴリズムの研究
  2. Jupiter Widget • http://jupyter.org/widgets.html • https://ipywidgets.readthedocs.io/en/latest/ • Jupyter Notebookに対話的な要素を追加する •

    対話的なデータ可視化 • Ipyleaflet、bplot、pythreejs • ZMQとWebSocketを使ったPython-JS間の値同期
  3. WebComponents • https://www.webcomponents.org/ • 独⾃自の振る舞いをするHTML要素を作成し
 配布、再利利⽤用する仕組み • 4つのWeb標準規格の総称 • CustomElements、HTML

    Templates、
 Shadow DOM、HTML Imports • WebComponentsを便便利利にするフレームワーク • Polymer、X-Tag、SkateJS、Bosonic
  4. EgRenderer • ⾃自作グラフ描画ライブラリ • canvasベース • トランジションを頑張る • めっちゃ作りかけ •

    WebGL対応したい • OGDFのレイアウトをサポートしたい • Emscripten (asm.js & WebAssembly) • https://likr.github.io/eg-renderer-canvas/
  5. HTML API 1 <!DOCTYPE html> 2 <html> 3 <head> 4

    <meta charset="utf-8"/> 5 <title>EgRenderer Example</title> 6 <script src="https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/0.7.22/ webcomponents.min.js"></script> 7 <link rel="import" href="../../eg-renderer.html"> 8 </head> 9 <body> 10 <eg-renderer 11 width="600" 12 height="400" 13 data='{ 14 "vertices": [ 15 {"u":0, "d": {"text": "source"}}, 16 {"u":1, "d": {"text": "target"}} 17 ], 18 "edges": [ 19 {"u": 0, "v": 1, "d": {}} 20 ] 21 }' 22 transition-duration="500" 23 layout="hierarchy"> 24 </eg-renderer> 25 </body> 26 </html>
  6. JS API 1 <!DOCTYPE html> 2 <html> 3 <head> 4

    <meta charset="utf-8"/> 5 <title>EgRenderer Example</title> 6 <script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/1.0.0/fetch.min.js"></script> 7 <script src="https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/0.7.22/ webcomponents.min.js"></script> 8 <link rel="import" href="../../eg-renderer.html"> 9 </head> 10 <body> 11 <eg-renderer 12 width="600" 13 height="400" 14 transition-duration="500" 15 layout="hierarchy"> 16 </eg-renderer> 17 <script> 18 fetch('data.json') 19 .then((response) => response.text()) 20 .then((data) => { 21 const renderer = document.querySelector('eg-renderer') 22 renderer.setAttribute('data', data) 23 renderer 24 .layout() 25 .center() 26 }) 27 </script> 28 </body> 29 </html>
  7. widget-cookiecutter • cookiecutter • https://github.com/audreyr/cookiecutter • プロジェクトテンプレート • Python製 •

    widget-cookiecutter • Jupyter Widget⽤用テンプレート • PyPI、npmへの配布が容易易 $ pip install cookiecutter $ cookiecutter https://github.com/jupyter/widget-cookiecutter.git
  8. Development • Pythonコードはpyegrenderer(プロジェクト名)以下 • JSコードはjs以下 • npmでモジュール管理理 • webpackで開発 $

    git clone https://github.com/likr/pyegrenderer.git $ cd pyegrenderer $ pip install -e . $ jupyter nbextension install --py --symlink --sys-prefix pyegrenderer $ jupyter nbextension enable --py --sys-prefix pyegrenderer
  9. トランスパイラとモジュールバンドラ • トランスパイラ • JSの機能を拡張、古いブラウザへの対応 • Babel、TypeScript • モジュールバンドラ •

    複数のJSファイル等を単⼀一のファイルにまとめる • Node.jsスタイルのプログラミング(CommonJS) • Webpack • widget-cookiecutterに標準搭載 • loaderでトランスパイルも可能
  10. js/webpack.config.js 6 var loaders = [ 7 { 8 test:

    /\.js$/, 9 include: [ 10 path.resolve(__dirname, 'src'), 11 path.resolve(__dirname, 'node_modules/eg-renderer-canvas') 12 ], 13 loader: 'babel-loader', 14 query: { 15 presets: ['latest'], 16 plugins: [ 17 'transform-custom-element-classes' 18 ] 19 } 20 }, 21 { 22 test: /\.json$/, 23 loader: 'json-loader' 24 } 25 ]
  11. js/src/example.js 25 // Custom View. Renders the widget model. 26

    const HelloView = widgets.DOMWidgetView.extend({ 27 render: function () { 28 this.model.on('change:data', () => { 29 const data = this.model.get('data') 30 this.component.setAttribute('data', data) 31 }) 32 33 this.model.on('change:layout_method', () => { 34 const layoutMethod = this.model.get('layout_method') 35 this.component.setAttribute('layout', layoutMethod) 36 }) 37 38 this.component = document.createElement('eg-renderer') 39 this.component.setAttribute('auto-update', '') 40 this.component.setAttribute('auto-centering', '') 41 this.component.setAttribute('transition-duration', '500') 42 this.component.setAttribute('width', '1000') 43 this.component.setAttribute('height', '750') 44 this.component.setAttribute('data', this.model.get('data')) 45 this.component.setAttribute('layout', this.model.get('layout_method')) 46 this.el.appendChild(this.component) 47 } 48 })
  12. pyegrenderer/example.py 1 import json 2 import ipywidgets as widgets 3

    from traitlets import Unicode 4 5 6 @widgets.register('hello.Hello') 7 class EgRenderer(widgets.DOMWidget): 8 """""" 9 _view_name = Unicode('HelloView').tag(sync=True) 10 _model_name = Unicode('HelloModel').tag(sync=True) 11 _view_module = Unicode('pyegrenderer').tag(sync=True) 12 _model_module = Unicode('pyegrenderer').tag(sync=True) 13 data = Unicode('{"vertices": [], "edges": []}').tag(sync=True) 14 layout_method = Unicode('hierarchy').tag(sync=True) 15 16 def render(self, graph): 17 vertices = [{'u': u, 'd': {'text': graph.node[u]['label']}} 18 for u in graph.nodes()] 19 edges = [{'u': u, 'v': v, 'd': {}} 20 for u, v in graph.edges()] 21 self.data = json.dumps({'vertices': vertices, 'edges': edges})
  13. まとめ • グラフ可視化するJupyter Widget作った • https://github.com/likr/pyegrenderer • widget-cookiecutterが便便利利だった • モダンなフロントエンドフレームワークの利利⽤用も可能

    • 今後も真⾯面⽬目に作るかは未定 • 既に本格的なグラフ可視化Widgetもあるよ! • https://github.com/cytoscape/jupyter-cytoscape