Skip to content

Instantly share code, notes, and snippets.

@nicain
Last active December 30, 2020 06:51
Show Gist options
  • Save nicain/7f165094e45e6363d5a7be5d034581dc to your computer and use it in GitHub Desktop.
Save nicain/7f165094e45e6363d5a7be5d034581dc to your computer and use it in GitHub Desktop.
import pandas as pd
from http.server import BaseHTTPRequestHandler, HTTPServer
import time
import bs4
from jinja2 import Template
from collections import OrderedDict
from bokeh.embed import components
from bokeh.models import Range1d
from bokeh.plotting import figure
from bokeh.resources import INLINE
from bokeh.util.browser import view
hostName = "localhost"
serverPort = 8080
class MyServer(BaseHTTPRequestHandler):
def do_GET(self):
data = {}
data['name'] = ['widget', 'fidget', 'digit']
data['sku'] = [123, 456, 000]
data['price'] = [7.89, 10.11, .111]
data['plot'] = ['__Red__', '__Blue__', '__Green__'] # "Anchor" points
df = pd.DataFrame(data)
table_text = df.to_html()
# create some data
x1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12]
y1 = [0, 8, 2, 4, 6, 9, 5, 6, 25, 28, 4, 7]
x2 = [2, 5, 7, 15, 18, 19, 25, 28, 9, 10, 4]
y2 = [2, 4, 6, 9, 15, 18, 0, 8, 2, 25, 28]
x3 = [0, 1, 0, 8, 2, 4, 6, 9, 7, 8, 9]
y3 = [0, 8, 4, 6, 9, 15, 18, 19, 19, 25, 28]
# select the tools we want
TOOLS="pan,wheel_zoom,box_zoom,reset,save"
# the red and blue graphs will share this data range
xr1 = Range1d(start=0, end=30)
yr1 = Range1d(start=0, end=30)
# only the green will use this data range
xr2 = Range1d(start=0, end=30)
yr2 = Range1d(start=0, end=30)
# build our figures
p1 = figure(x_range=xr1, y_range=yr1, tools=TOOLS, plot_width=300, plot_height=300)
p1.scatter(x1, y1, size=12, color="red", alpha=0.5)
p2 = figure(x_range=xr1, y_range=yr1, tools=TOOLS, plot_width=300, plot_height=300)
p2.scatter(x2, y2, size=12, color="blue", alpha=0.5)
p3 = figure(x_range=xr2, y_range=yr2, tools=TOOLS, plot_width=300, plot_height=300)
p3.scatter(x3, y3, size=12, color="green", alpha=0.5)
script1, (div1, div2, div3) = components([p1, p2, p3])
# Turn all "th" headers to buttons:
soup = bs4.BeautifulSoup(table_text, features="html.parser")
for x in soup.find_all('th'):
if x.string is not None:
tag = soup.new_tag(name="button")
tag['type'] = "button"
tag.string = 'Delete'
x.string.insert_after(tag)
# Insert plots into "anchor" points, defined in the dataframe:
for anchor, div in {'__Red__':div1, '__Green__':div2, '__Blue__':div3}.items():
x = soup.find(string=anchor)
tmp = bs4.BeautifulSoup('<div class="embed-wrapper">'+div.strip()+'</div>')
x.replace_with(tmp)
table_text = soup.prettify(formatter="minimal")
template = Template('''<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Bokeh Scatter Plots</title>
{{ resources }}
{{ script1 }}
<style>
.embed-wrapper {
display: flex;
justify-content: space-evenly;
}
</style>
</head>
<body>
{{ table_text }}
</body>
</html>
''')
html = template.render(resources=INLINE.render(),
script1=script1,
div1=div1, div2=div2, div3=div3,
table_text=table_text)
self.send_response(200)
self.send_header("Content-type", "text/html")
self.end_headers()
self.wfile.write(bytes(html, "utf-8"))
if __name__ == "__main__":
webServer = HTTPServer((hostName, serverPort), MyServer)
print("Server started http://%s:%s" % (hostName, serverPort))
try:
webServer.serve_forever()
except KeyboardInterrupt:
pass
webServer.server_close()
print("Server stopped.")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment