Search code examples
bokehtornadopython-3.8

Image not showing with a standalone bokeh server using BokehTornado instance configured with StaticFileHandler


This is a follow up of my previous question.

The structure of the files is shown below. I have to run the scripts using python -m bokeh_module.bokeh_sub_module from the top directory. The image.png might come from an arbitrary directory later.

.
├── other_module
│   ├── __init__.py
│   └── other_sub_module.py
├── bokeh_module
│   ├── __init__.py
│   ├── image.png # not showing
│   └── bokeh_sub_module.py
└── image.png # not showing either

The bokeh_sub_module.py is using the standalone bokeh server. However the image will not show no matter where it is placed. I got this WARNING:tornado.access:404 GET /favicon.ico (::1) 0.50ms I'm not sure if this an issue from bokeh or tornado. Thank you for any help.

from other_module import other_sub_module
import os
from bokeh.server.server import Server
from bokeh.layouts import column
from bokeh.plotting import figure, show
import tornado.web

def make_document(doc):
    def update():
        pass

    # do something with other_sub_module
    p = figure(match_aspect=True)
    p.image_url( ['file://image.png'], 0, 0, 1, 1)
    doc.add_root(column(p, sizing_mode='stretch_both'))
    doc.add_periodic_callback(callback=update, period_milliseconds=1000)


apps = {'/': make_document}
application = tornado.web.Application([(r"/(.*)", \
                                      tornado.web.StaticFileHandler, \
                                      {"path": os.path.dirname(__file__)}),])
server = Server(apps, tornado_app=application)
server.start()
server.io_loop.add_callback(server.show, "/")
server.io_loop.start()

I tried the argument extra_patterns and it does not work either...


Solution

  • You cannot use the file:// protocol with web servers and browsers. Just use regular http:// or https://. If you specify the correct URL, the StaticFileHandler should properly handle it.

    Apart from that, your usage of Server is not correct. It doesn't have the tornado_app argument. Instead, pass the routes directly:

    extra_patterns = [(r"/(.*)", tornado.web.StaticFileHandler,
                       {"path": os.path.dirname(__file__)})]
    server = Server(apps, extra_patterns=extra_patterns)
    

    BTW just in case - in general, you shouldn't serve the root of your app. Otherwise, anyone would be able to see your source code.