Using bokeh server in jupyter notebook behind proxy / jupyterhub - jupyter-notebook

I want to develop bokeh apps on a jupyter notebook instance that runs behind jupyterhub (AKA an authenticating proxy). I would like to have interactive bokeh apps calling back to the notebook kernel. I don't want to use the notebook widgets etc because I want to be able to export the notebook as a python file and have something I can serve with bokeh server.
The following code in my notebook gives an empty output with no errors:
from bokeh.layouts import row
from bokeh.models.widgets import Button
from bokeh.io import show, output_notebook
from bokeh.application.handlers import FunctionHandler
from bokeh.application import Application
output_notebook()
# Create the Document Application
def modify_doc(doc):
layout = row(Button(label="Hello,"),Button(label="world!"))
doc.add_root(layout)
handler = FunctionHandler(modify_doc)
app = Application(handler)
# Output = BokehJS 0.12.10 successfully loaded.
# New cell
show(app, notebook_url="my-jupyterhub-url.com:80")
# Output = "empty" cell
Inspecting the cell a script tag has been added:
<script src="http://my-jupyterhub-url.com:46249/autoload.js?bokeh-autoload-element=f8fa3bd0-9caf-473d-87a5-6c7b9680648b&bokeh-absolute-url=http://my-jupyterhub-url.com:46249" id="f8fa3bd0-9caf-473d-87a5-6c7b9680648b" data-bokeh-model-id="" data-bokeh-doc-id=""></script>
This will not work because port 46249 isn't open on the jupyterhub proxy. Also the path that routes to my jupyter instance is my-jupyterhub-url.com/user/my-username/ so my-jupyterhub-url.com/autoload.js wouldn't route anywhere.
This feels like it could be a common requirement but a search hasn't revealed a solution to be yet.
Any ideas?

So I've found a solution that I'm not happy about but works.. just about.
First install nbserverproxy on your Jupyter instance. This allows you to proxy through JupyterHub (where you are authenticated) onto arbitrary ports on your Jupyter machine/container. I installed by opening a terminal from the Jupyter web front end and typing:
pip install git+https://github.com/jupyterhub/nbserverproxy --user
jupyter serverextension enable --py nbserverproxy --user
Then restart your server. For my install of JupyterHub this was control panel -> stop my server wait then start my server.
Finally I monkey patched the Ipython.display.publish_display_data (since the source code revealed that bokeh used this when calling show) in the notebook like so.
from unittest.mock import patch
from IPython.display import publish_display_data
orig = publish_display_data
import re
def proxy_replacer(display_data):
for key, item in display_data.items():
if isinstance(item, str):
item= re.sub(r'(/user/tam203)/?:([0-9]+)', r'\1/proxy/\2', item)
item = re.sub(r'http:' , 'https:', item)
display_data[key] = item
return display_data
def mock(data, metadata=None, source=None):
data = proxy_replacer(data) if data else data
metadata = proxy_replacer(metadata) if metadata else metadata
return orig(data, metadata=metadata, source=source)
patcher = patch('IPython.display.publish_display_data', new=mock)
patcher.start()
With that all done I was then able to run the following an see a nice dynamically updating plot.
import random
from bokeh.io import output_notebook
output_notebook()
from bokeh.io import show
from bokeh.server.server import Server
from bokeh.application import Application
from bokeh.application.handlers.function import FunctionHandler
from bokeh.plotting import figure, ColumnDataSource
def make_document(doc):
source = ColumnDataSource({'x': [], 'y': [], 'color': []})
def update():
new = {'x': [random.random()],
'y': [random.random()],
'color': [random.choice(['red', 'blue', 'green'])]}
source.stream(new)
doc.add_periodic_callback(update, 100)
fig = figure(title='Streaming Circle Plot!', sizing_mode='scale_width',
x_range=[0, 1], y_range=[0, 1])
fig.circle(source=source, x='x', y='y', color='color', size=10)
doc.title = "Now with live updating!"
doc.add_root(fig)
app = Application(FunctionHandler(make_document))
show(app, notebook_url="<my-domain>.co.uk/user/tam203/")
So while I'm happy to have found a work around it doesn't really feel like a solution. I think a smallish change in bokeh could solve this (something like a url template string where you can specify the path and the port).

According to the official bokeh documentation show(obj, notebook_url=remote_jupyter_proxy_url) accepts a notebook_url argument value. Apparently this can be a function that accepts a port argument value.
The documentation goes further by providing a reference implementation for the function remote_jupyter_proxy_url in the context of jupyterhub/jupyterlab and proxy extension.

Related

tqdm in Jupyter notebook does not show up

I would like to implement a progress bar in Jupyter notebook. I tried using tqdm as shown in the code below, but I just get this shown on the screen and the progress bar is...well...not progressing:
CODE
# Iterate through each sound file and extract the features
from tqdm import tqdm
items = len(metadata.index)
for i in tqdm(range(items), "Completed"):
for index, row in metadata.iterrows():
file_name = os.path.join(os.path.abspath(fulldatasetpath),'fold'+str(row["fold"])+'/',str(row["slice_file_name"]))
class_label = row["class_name"]
data = extract_features(file_name)
features.append([data, class_label])
Can you help me get the progress bar to progress? Thanks!
For Jupyter notebooks you should use a special version of tqdm:
from tqdm.notebook import tqdm

AutocompleteInput does not complete word when option is clicked

I'm working in Jupyter notebook 5.7.4 bokeh 1.0.4, Firefox 63.0.3 python3.7, I want to get autocompletion using bokeh to get some interactive visualization.
from bokeh.models.widgets import AutocompleteInput
from IPython.display import HTML
input_widget = AutocompleteInput(completions=cList1, title='FTTH Keys', value='value')
l = layout([[input_widget],], sizing_mode='fixed')
curdoc().add_root(l)
curdoc().title = 'UI Test'
show(l)
when I write characters all is fine, but when I want to choose one element from the autocomplete list the word didn't complete in the input box.

Upload images with labels in google collab

I am using jupyter notebook in google collab. My training dataset looks like this:
/data/label1/img1.jpeg
.
.
.
/data/label2/img90.jpeg
I want to import such dataset. Things that I tried
Step1:
!pip install -U -q PyDrive
%matplotlib inline
import matplotlib
import matplotlib.pyplot as plt
from os import walk
import os
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
from google.colab import auth
from oauth2client.client import GoogleCredentials
Step 2:
# 1. Authenticate and create the PyDrive client.
auth.authenticate_user()
gauth = GoogleAuth()
gauth.credentials = GoogleCredentials.get_application_default()
drive = GoogleDrive(gauth)
Step 3
file_to_download = os.path.expanduser('./data/')
file_list = drive.ListFile(
{'q': 'id_of_the_data_directory'})
Not sure how to proceed next. The folder data is my collab notebook folder in the drive. I want to read the images along with labels.In order to do the same I am using the code:
filename_queue=tf.train.string_input_producer(tf.train.match_filenames_once('data/*/*.jpeg'))
image_reader=tf.WholeFileReader()
key,image_file=image_reader.read(filename_queue)
#key is the entire path to the jpeg file and we need only the subfolder as the label
S = tf.string_split([key],'\/')
length = tf.cast(S.dense_shape[1],tf.int32)
label = S.values[length-tf.constant(2,dtype=tf.int32)]
label = tf.string_to_number(label,out_type=tf.int32)
#decode the image
image=tf.image.decode_jpeg(image_file)
#then code to place labels and folders in corresponding arrays
You should upload your dataset in a recursive manner. Here is a sample on how to upload your dataset from your Google Drive to Colab
First of all I want to mention that we cannot access the folder directly. We need to set the mount point and all the drive contents are accessed via that. Thanks to this answer
Follow the steps exactly as given in the answer link given above. But just make sure to change your path according to the new drive folder created.
PS: I still left the question open because you may reach here with image dataset having subfolder names as the labels of the training images, it works for so the solution posted here works for both directories with subfolders as well as directories with files.

Unable to set bokeh plotting parameters using BOKEH + HOLOVIEW plotting option via Python

Is there any documentation specifying how to pass Bokeh parameters via holoview?
I am reading the tutorials but I think there is something small I have missed.
There is an example online which describes this in Ipython but I am trying to do it via a python WITHOUT Ipython notebook.
http://holoviews.org/Tutorials/Bokeh_Backend.html?highlight=bokeh
When I run this program I get the curves but the color does not change and I also get this error: WARNING:root:Curve01537: Setting non-parameter attribute style={'line_color': 'green'} using a mechanism intended only for parameters
How can we set the parameter?
Code Example here
from pprint import pprint, pformat
import holoviews as hv
import numpy as np
import pathlib, os
import webbrowser
import lasio, las
from holoviews import Store
from holoviews.plotting.bokeh.element import (line_properties, fill_properties, text_properties)
def plot_bokeh(plot):
#Create renderer instance
myrenderer = hv.Store.renderers['bokeh'].instance(fig='html')
out_file_name = "".join(["./OUTPUT/","gyro", "_graph.html"])
with open (out_file_name, 'w') as f:
#Plot static html
f.write (myrenderer.static_html(plot))
f.close()
webbrowser.open_new_tab(pathlib.Path(os.path.abspath(out_file_name)).as_uri())
def holoview_sandbox():
curve_opts = dict(line_color='green')
xs = np.linspace(0, np.pi*4, 100)
data = (xs, np.sin(xs))
holo_plot = hv.Curve(data, label='MY LABEL' , style=curve_opts)
plot_bokeh(holo_plot)
if __name__ == '__main__':
holoview_sandbox()
In HoloViews the options aren't bound to the objects themselves, which has various benefits including being able to plot with different backends. The pure-Python way of setting style options is this:
curve_opts = dict(line_color='green')
xs = np.linspace(0, np.pi*4, 100)
data = (xs, np.sin(xs))
holo_plot = hv.Curve(data, label='MY LABEL')(style=curve_opts)
The Options Tutorial describes how to set options like this, but please let us know if you found some of that unclear.
This syntax works as well
holo_plot.opts(style={'color': 'green'})
When you change the entry 'line_color' to 'color' in the dict() of Philipp's answer, then this works for the matplotlib backend as well.
Details about setting options can also be found here in addition to Philipp's link.

Animated graphs in ipython notebook

Is there a way of creating animated graphs. For example showing the same graph, with different parameters.
For example is SAGE notebook, one can write:
a = animate([circle((i,i), 1-1/(i+1), hue=i/10) for i in srange(0,2,0.2)],
xmin=0,ymin=0,xmax=2,ymax=2,figsize=[2,2])
a.show()
This has horrible flickering, but at least this creates a plot that animates for me. It is based on Aron's, but Aron's does not work as-is.
import time, sys
from IPython.core.display import clear_output
f, ax = plt.subplots()
n = 30
x = array([i/10.0 for i in range(n)])
y = array([sin(i) for i in x])
for i in range(5,n):
ax.plot(x[:i],y[:i])
time.sleep(0.1)
clear_output()
display(f)
ax.cla() # turn this off if you'd like to "build up" plots
plt.close()
Update: January 2014
Jake Vanderplas has created a Javascript-based package for matplotlib animations available here. Using it is as simple as:
# https://github.com/jakevdp/JSAnimation
from JSAnimation import examples
examples.basic_animation()
See his blog post for a more complete description and examples.
Historical answer (see goger for a correction)
Yes, the Javascript update does not correctly hold the image frame yet, so there is flicker, but you can do something quite simple using this technique:
import time, sys
from IPython.display import clear_output
f, ax = plt.subplots()
for i in range(10):
y = i/10*sin(x)
ax.plot(x,y)
time.sleep(0.5)
clear_output()
display(f)
ax.cla() # turn this off if you'd like to "build up" plots
plt.close()
IPython widgets let you manipulate Python objects in the kernel with GUI objects in the Notebook. You might also like Sage hosted IPython Notebooks. One problem you might have with sharing widgets or interactivity in Notebooks is that if someone else doesn't have IPython, they can't run your work. To solve that, you can use Domino to share Notebooks with widgets that others can run.
Below are three examples of widgets you can build in a Notebook using pandas to filter data, fractals, and a slider for a 3D plot. Learn more and see the code and Notebooks here.
If you want to live-stream data or set up a simulation to run as a loop, you can also stream data into plots in a Notebook. Disclaimer: I work for Plotly.
If you use IPython notebook, v2.0 and above support interactive widgets. You can find a good example notebook here (n.b. you need to download and run from your own machine to see the sliders).
It essentially boils down to importing interact, and then passing it a function, along with ranges for the paramters. e.g., from the second link:
In [8]:
def pltsin(f, a):
plot(x,a*sin(2*pi*x*f))
ylim(-10,10)
In [9]:
interact(pltsin, f=(1,10,0.1), a=(1,10,1));
This will produce a plot with two sliders, for f and a.
If you want 3D scatter plot animations, the Ipyvolume Jupyter widget is very impressive.
http://ipyvolume.readthedocs.io/en/latest/animation.html#
bqplot is a really good option to do this now. its built specifically for animation through python in the notebook
https://github.com/bloomberg/bqplot
On #goger's comment of 'horrible flickering', I found that calling clear_output(wait=True) solved my problem. The flag tells clear_output to wait to render till it has something new to render.
matplotlib has an animation module to do just that. However, examples provided on the site will not run as is in a notebook; you need to make a few tweaks to make it work.
Here is the example of the page below modified to work in a notebook (modifications in bold).
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from matplotlib import rc
from IPython.display import HTML
fig, ax = plt.subplots()
xdata, ydata = [], []
ln, = plt.plot([], [], 'ro', animated=True)
def init():
ax.set_xlim(0, 2*np.pi)
ax.set_ylim(-1, 1)
return ln,
def update(frame):
xdata.append(frame)
ydata.append(np.sin(frame))
ln.set_data(xdata, ydata)
return ln,
ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
init_func=init, blit=True)
rc('animation', html='html5')
ani
# plt.show() # not needed anymore
Note that the animation in the notebook is made via a movie and that you need to have ffmpeg installed and matplotlib configured to use it.

Resources