Repository: bokeh/bokeh

Issue:
Missing template in flask_embed.py and tornado_embed.py
The `flask_embed.py` and `tornado_embed.py` examples are not self-contained in that they need an `embed.html` template. Running `flask_embed.py` as it appears in the repository leads to the following error:

```
$ python flask_embed.py 
Opening Flask app with embedded Bokeh application on http://localhost:8080/
[2017-01-16 21:29:37,150] ERROR in app: Exception on / [GET]
Traceback (most recent call last):
  File "/home/juanlu/.miniconda3/envs/py35/lib/python3.5/site-packages/flask/app.py", line 1982, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/juanlu/.miniconda3/envs/py35/lib/python3.5/site-packages/flask/app.py", line 1614, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/juanlu/.miniconda3/envs/py35/lib/python3.5/site-packages/flask/app.py", line 1517, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/home/juanlu/.miniconda3/envs/py35/lib/python3.5/site-packages/flask/_compat.py", line 33, in reraise
    raise value
  File "/home/juanlu/.miniconda3/envs/py35/lib/python3.5/site-packages/flask/app.py", line 1612, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/juanlu/.miniconda3/envs/py35/lib/python3.5/site-packages/flask/app.py", line 1598, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "flask_embed.py", line 43, in bkapp_page
    return render_template("embed.html", script=script)
  File "/home/juanlu/.miniconda3/envs/py35/lib/python3.5/site-packages/flask/templating.py", line 133, in render_template
    return _render(ctx.app.jinja_env.get_or_select_template(template_name_or_list),
  File "/home/juanlu/.miniconda3/envs/py35/lib/python3.5/site-packages/jinja2/environment.py", line 851, in get_or_select_template
    return self.get_template(template_name_or_list, parent, globals)
  File "/home/juanlu/.miniconda3/envs/py35/lib/python3.5/site-packages/jinja2/environment.py", line 812, in get_template
    return self._load_template(name, self.make_globals(globals))
  File "/home/juanlu/.miniconda3/envs/py35/lib/python3.5/site-packages/jinja2/environment.py", line 774, in _load_template
    cache_key = self.loader.get_source(self, name)[1]
  File "/home/juanlu/.miniconda3/envs/py35/lib/python3.5/site-packages/flask/templating.py", line 57, in get_source
    return self._get_source_fast(environment, template)
  File "/home/juanlu/.miniconda3/envs/py35/lib/python3.5/site-packages/flask/templating.py", line 85, in _get_source_fast
    raise TemplateNotFound(template)
jinja2.exceptions.TemplateNotFound: embed.html
```

And putting `examples/embed/simple/templates/embed.html` under `templates/` yields this:

```
$ python flask_embed.py   
Opening Flask app with embedded Bokeh application on http://localhost:8080/
[2017-01-16 21:30:38,094] ERROR in app: Exception on / [GET]
Traceback (most recent call last):
  File "/home/juanlu/.miniconda3/envs/py35/lib/python3.5/site-packages/flask/app.py", line 1982, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/juanlu/.miniconda3/envs/py35/lib/python3.5/site-packages/flask/app.py", line 1614, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/juanlu/.miniconda3/envs/py35/lib/python3.5/site-packages/flask/app.py", line 1517, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/home/juanlu/.miniconda3/envs/py35/lib/python3.5/site-packages/flask/_compat.py", line 33, in reraise
    raise value
  File "/home/juanlu/.miniconda3/envs/py35/lib/python3.5/site-packages/flask/app.py", line 1612, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/juanlu/.miniconda3/envs/py35/lib/python3.5/site-packages/flask/app.py", line 1598, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "flask_embed.py", line 43, in bkapp_page
    return render_template("embed.html", script=script)
  File "/home/juanlu/.miniconda3/envs/py35/lib/python3.5/site-packages/flask/templating.py", line 134, in render_template
    context, ctx.app)
  File "/home/juanlu/.miniconda3/envs/py35/lib/python3.5/site-packages/flask/templating.py", line 116, in _render
    rv = template.render(context)
  File "/home/juanlu/.miniconda3/envs/py35/lib/python3.5/site-packages/jinja2/environment.py", line 989, in render
    return self.environment.handle_exception(exc_info, True)
  File "/home/juanlu/.miniconda3/envs/py35/lib/python3.5/site-packages/jinja2/environment.py", line 754, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/home/juanlu/.miniconda3/envs/py35/lib/python3.5/site-packages/jinja2/_compat.py", line 37, in reraise
    raise value.with_traceback(tb)
  File "/tmp/templates/embed.html", line 9, in top-level template code
    {{ js_resources|indent(4)|safe }}
  File "/home/juanlu/.miniconda3/envs/py35/lib/python3.5/site-packages/jinja2/filters.py", line 453, in do_indent
    rv = (u'\n' + indention).join(s.splitlines())
jinja2.exceptions.UndefinedError: 'js_resources' is undefined
```


Discussion:
Ack, I think it did not get picked up during the last release because of a `.gitignore` excluding HTML files. And it's since been deleted in my local tree. The other `embed.html` is not appropriate for this context, I will add a suitable one to master soon. 
In the mean time, the template just needs a place for 
```
{{ script }}
```
as can be seen by the render call:
```
self.write(template.render(script=script))
```
I'm actually putting out several fires at the moment, if you have the ability to make a small PR adding a simple but interesting `embed.html` with a `{{ script }}` placeholder, it would be very valuable and appreciated. 
@Juanlu001 are you interested in submitting a PR to resolve this issue as described above?
@bryevdv I am indeed, but won't be able to work on this earlier than next weekend I fear!
Great! I just wanted to make sure you had the opportunity to, if you wanted to, before anyone else worked on it. :)
FYI I needed to show this to someone, so I created this right quick:
```
<!doctype html>

<html lang="en">

  <head>
    <meta charset="utf-8">
    <title>App</title>
  </head>

  <body>
    <div>HERE IS SOME CUSTOM STUFF</div>
    {{ script|safe }}
  </body>

</html>
```
It would great if this could be made a little more interesting or visually appealing!

Resolving patch:
diff --git a/examples/embed/autoload_static.py b/examples/embed/autoload_static.py
new file mode 100644
--- /dev/null
+++ b/examples/embed/autoload_static.py
@@ -0,0 +1,72 @@
+from jinja2 import Template
+
+from tornado.ioloop import IOLoop
+from tornado.web import Application, RequestHandler
+
+from bokeh.embed import autoload_static
+from bokeh.plotting import figure
+from bokeh.resources import CDN
+from bokeh.sampledata.iris import flowers
+from bokeh.util.browser import view
+
+template = Template("""
+<!doctype html>
+
+<html lang="en">
+<head>
+  <meta charset="utf-8">
+</head>
+
+<body>
+  <div>
+    The plot embedded below is a standalone plot that was embedded using
+    <fixed>autoload_server</fixed>. For more information see the
+    <a target="_blank" href="http://bokeh.pydata.org/en/latest/docs/user_guide/embed.html#static-data">
+    documentation</a>.
+  </div>
+  {{ script|safe }}
+</body>
+</html>
+""")
+
+class IndexHandler(RequestHandler):
+    def initialize(self, script):
+        self.script = script
+    def get(self):
+        self.write(template.render(script=self.script))
+
+# Normally, you might save the .js files to some location on disk, and serve
+# them from there. Here we us this request handler, just to make the example
+# completely self-contained.
+class JSHandler(RequestHandler):
+    def initialize(self, js):
+        self.js = js
+    def get(self): self.write(self.js)
+
+def make_plot():
+    colormap = {'setosa': 'red', 'versicolor': 'green', 'virginica': 'blue'}
+    colors = [colormap[x] for x in flowers['species']]
+
+    p = figure(title = "Iris Morphology")
+    p.xaxis.axis_label = 'Petal Length'
+    p.yaxis.axis_label = 'Petal Width'
+
+    p.circle(flowers["petal_length"], flowers["petal_width"],
+             color=colors, fill_alpha=0.2, size=10)
+
+    return p
+
+if __name__ == '__main__':
+    print('Opening Tornado app with embedded Bokeh plot on http://localhost:8888/')
+
+    js, script = autoload_static(make_plot(), CDN, "embed.js")
+
+    app = Application([
+        (r"/", IndexHandler, dict(script=script)),
+        (r"/embed.js", JSHandler, dict(js=js))
+    ])
+    app.listen(8888)
+
+    io_loop = IOLoop.current()
+    io_loop.add_callback(view, "http://localhost:8888/")
+    io_loop.start()
diff --git a/examples/howto/server_embed/flask_embed.py b/examples/howto/server_embed/flask_embed.py
--- a/examples/howto/server_embed/flask_embed.py
+++ b/examples/howto/server_embed/flask_embed.py
@@ -5,7 +5,7 @@
 from bokeh.application import Application
 from bokeh.application.handlers import FunctionHandler
 from bokeh.embed import autoload_server
-from bokeh.layouts import column
+from bokeh.layouts import row, widgetbox
 from bokeh.models import ColumnDataSource, Slider
 from bokeh.plotting import figure
 from bokeh.server.server import Server
@@ -18,7 +18,7 @@ def modify_doc(doc):
 
     source = ColumnDataSource(data=dict(x=x, y=y))
 
-    plot = figure()
+    plot = figure(title="Simple plot with slider")
     plot.line('x', 'y', source=source)
 
     slider = Slider(start=1, end=10, value=1, step=0.1)
@@ -28,7 +28,7 @@ def callback(attr, old, new):
         source.data = dict(x=x, y=y)
     slider.on_change('value', callback)
 
-    doc.add_root(column(slider, plot))
+    doc.add_root(row(widgetbox(slider), plot))
 
 bokeh_app = Application(FunctionHandler(modify_doc))
 
@@ -40,7 +40,7 @@ def callback(attr, old, new):
 @flask_app.route('/', methods=['GET'])
 def bkapp_page():
     script = autoload_server(model=None, url='http://localhost:5006/bkapp')
-    return render_template("embed.html", script=script)
+    return render_template("embed.html", script=script, template="Flask")
 
 if __name__ == '__main__':
     from tornado.httpserver import HTTPServer
diff --git a/examples/howto/server_embed/tornado_embed.py b/examples/howto/server_embed/tornado_embed.py
--- a/examples/howto/server_embed/tornado_embed.py
+++ b/examples/howto/server_embed/tornado_embed.py
@@ -7,7 +7,7 @@
 from bokeh.application import Application
 from bokeh.application.handlers import FunctionHandler
 from bokeh.embed import autoload_server
-from bokeh.layouts import column
+from bokeh.layouts import row, widgetbox
 from bokeh.models import ColumnDataSource, Slider
 from bokeh.plotting import figure
 from bokeh.server.server import Server
@@ -18,7 +18,7 @@ class IndexHandler(RequestHandler):
     def get(self):
         template = env.get_template('embed.html')
         script = autoload_server(model=None, url='http://localhost:5006/bkapp')
-        self.write(template.render(script=script))
+        self.write(template.render(script=script, template="Tornado"))
 
 def modify_doc(doc):
     x = np.linspace(0, 10, 1000)
@@ -26,7 +26,7 @@ def modify_doc(doc):
 
     source = ColumnDataSource(data=dict(x=x, y=y))
 
-    plot = figure()
+    plot = figure(title="Simple plot with slider")
     plot.line('x', 'y', source=source)
 
     slider = Slider(start=1, end=10, value=1, step=0.1)
@@ -36,7 +36,7 @@ def callback(attr, old, new):
         source.data = dict(x=x, y=y)
     slider.on_change('value', callback)
 
-    doc.add_root(column(slider, plot))
+    doc.add_root(row(widgetbox(slider), plot))
 
 bokeh_app = Application(FunctionHandler(modify_doc))
 


Test patch: