def init_notebook():
    
    from IPython.display import display, Javascript, HTML
    
    # todo: ideally you don't want user interactions done this way:
    # they result in spamming of JavaScript "objects" and when nbconverting,
    # this will result in a huge number of output_javascript elements.
    def my_send_command(command):
        display(Javascript('flexx.command(%s);' % reprs(command)))
    
    # Create default session and monkey-patch it
    # Not very pretty, but this keeps notebook logic confined to this module/function.
    session = manager.get_default_session()
    if hasattr(session, '_original_send_command'):
        display(HTML("<i>Flexx already loaded</i>"))
        return  # Don't inject twice
    else:
        session._original_send_command = session._send_command
        session._send_command = my_send_command
        try:
            session.use_global_asset('phosphor-all.js')
            session.use_global_asset('flexx-ui.css')
            session.use_global_asset('flexx-ui.js')
        except IndexError:
            pass  # Ok if it fails; assets can be loaded dynamically.
    
    # Open server - we only use websocket for JS-to-Py communication
    _server_open()
    host, port = server.serving_at
    asset_elements = session.get_assets_as_html()
    
    # Make the JS that we inject not take any vertical space when nbconverted
    extra_css = '.output_subarea.output_javascript { padding: 0px; }'
    
    # Compose HTML to inject
    url = 'ws://%s:%i/%s/ws' % (host, port, session.app_name)
    t = "<i>Injecting Flexx JS and CSS</i>"
    t += '\n\n'.join(asset_elements)
    t += '\n\n<style>%s</style>\n' % extra_css
    t += "<script>flexx.ws_url='%s'; " % url
    t += "flexx.is_notebook=true; flexx.init();</script>"
    
    display(HTML(t))
Initialize the Jupyter notebook by injecting the necessary CSS
dataset/ETHPy150Open zoofIO/flexx/flexx/app/funcs.py/init_notebook