bokeh.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. import asyncio
  2. import re
  3. from collections.abc import Sequence
  4. from pywebio.session import get_info
  5. from pywebio.output import *
  6. requirejs_tpl = """
  7. %s
  8. <script type="text/javascript">
  9. requirejs(['bokeh', 'bokeh-widgets', 'bokeh-tables', 'bokeh-gl'], function(Bokeh) {
  10. %s
  11. });
  12. </script>
  13. """
  14. def load_notebook(resources=None, verbose=False, hide_banner=False, load_timeout=5000):
  15. """加载 Bokeh 资源
  16. :param resources: 目前不支持自定义静态资源的链接
  17. :param verbose: 开启 Bokeh 日志 并显示 Bokeh 加载标签
  18. :param hide_banner: 不支持
  19. :param load_timeout: 不支持
  20. :return: None
  21. """
  22. from bokeh.util.serialization import make_id
  23. js_gists = ["console.log('Load BokehJS complete.')"]
  24. html = ''
  25. if verbose:
  26. element_id = make_id()
  27. html += """
  28. <div class="bk-root">
  29. <a href="https://bokeh.org" target="_blank" class="bk-logo bk-logo-small bk-logo-notebook"></a>
  30. <span id="{element_id}" style="font-family: Helvetica, Arial, sans-serif;font-size: 13px;">Loading BokehJS ...</span>
  31. </div>
  32. """.format(element_id=element_id)
  33. js_gists.append(
  34. "document.getElementById({element_id}).innerHTML = 'Load BokehJS complete.'".format(element_id=element_id))
  35. js_gists.append('Bokeh.set_log_level("info");')
  36. js_gists.append("console.log('Set bokeh log level to INFO because you set `output_notebook(verbose=True)`')")
  37. put_html(requirejs_tpl % (html, '\n'.join(js_gists)), sanitize=False)
  38. def show_doc(obj, state, notebook_handle):
  39. """Show a document of Bokeh
  40. :param obj:
  41. :param state:
  42. :param notebook_handle: 不支持
  43. :return:
  44. """
  45. from bokeh.embed import components
  46. script, div = components(obj, wrap_script=False)
  47. if isinstance(obj, Sequence):
  48. div = '\n'.join(div)
  49. elif isinstance(obj, dict):
  50. div = '\n'.join(div[k] for k in obj.keys())
  51. put_html(requirejs_tpl % (div, script), sanitize=False)
  52. def show_app(app, state, notebook_url, port=0, **kw):
  53. """Show Bokeh applications
  54. :param app: A Bokeh Application to embed in PyWebIO.
  55. :param state: ** Unused **
  56. :param notebook_url: ** Unused **
  57. :param port: Bokeh Server 端口
  58. :param kw: 传给 Bokeh Server 的额外参数
  59. """
  60. from bokeh.server.server import Server
  61. from bokeh.io.notebook import _origin_url, uuid4, curstate, _server_url
  62. from pywebio.platform.tornado import ioloop
  63. loop = ioloop()
  64. loop.make_current()
  65. asyncio.set_event_loop(loop.asyncio_loop)
  66. # loop = IOLoop.current()
  67. info = get_info()
  68. allow_websocket_origin = [info.server_host]
  69. if info.origin:
  70. allow_websocket_origin.append(_origin_url(info.origin))
  71. server = Server({"/": app}, io_loop=loop, port=port, allow_websocket_origin=allow_websocket_origin, **kw)
  72. server_id = uuid4().hex
  73. curstate().uuid_to_server[server_id] = server
  74. server.start()
  75. url = _server_url(info.server_host, server.port)
  76. from bokeh.embed import server_document
  77. script = server_document(url, resources=None)
  78. script = re.sub(r'<script(.*?)>([\s\S]*?)</script>', r"""
  79. <script \g<1>>
  80. requirejs(['bokeh', 'bokeh-widgets', 'bokeh-tables', 'bokeh-gl'], function(Bokeh) {
  81. \g<2>
  82. });
  83. </script>
  84. """, script)
  85. put_html(script, sanitize=False)
  86. def try_install_bokeh_hook():
  87. """尝试安装bokeh支持"""
  88. try:
  89. from bokeh.io import install_notebook_hook
  90. except ImportError:
  91. return False
  92. install_notebook_hook('pywebio', load_notebook, show_doc, show_app)
  93. return True