Is it possible to run bokeh widget python callbacks in jupyter notebook - jupyter-notebook

I'm working in the jupyter notebook.
Is it possible to run python callbacks from a bokeh widget?

Yes, you can embed a bokeh server app in a Jupyter notebook by defining a function that modifies a Bokeh document, and passes it to show, e.g.:
def modify_doc(doc):
df = sea_surface_temperature.copy()
source = ColumnDataSource(data=df)
plot = figure(x_axis_type='datetime', y_range=(0, 25),
y_axis_label='Temperature (Celsius)',
title="Sea Surface Temperature at 43.18, -70.43")
plot.line('time', 'temperature', source=source)
def callback(attr, old, new):
if new == 0:
data = df
else:
data = df.rolling('{0}D'.format(new)).mean()
source.data = ColumnDataSource(data=data).data
slider = Slider(start=0, end=30, value=0, step=1, title="Smoothing by N Days")
slider.on_change('value', callback)
doc.add_root(column(slider, plot))
You can see a complete example here:
https://github.com/bokeh/bokeh/blob/master/examples/howto/server_embed/notebook_embed.ipynb
(You will need to run the notebook locally)

Related

Is there a way to prevent scrolling of an iPython notebook, when calling 'mouse_scroll' event over a plot figure inside a cell?

Is there a way to prevent the entire notebook from scrolling, when scrolling over the figure to cycle through the images as shown in this example (and reproduced below): https://matplotlib.org/stable/gallery/event_handling/image_slices_viewer.html
import numpy as np
import matplotlib.pyplot as plt
# Fixing random state for reproducibility
np.random.seed(19680801)
class IndexTracker:
def __init__(self, ax, X):
self.ax = ax
ax.set_title('use scroll wheel to navigate images')
self.X = X
rows, cols, self.slices = X.shape
self.ind = self.slices//2
self.im = ax.imshow(self.X[:, :, self.ind])
self.update()
def on_scroll(self, event):
print("%s %s" % (event.button, event.step))
if event.button == 'up':
self.ind = (self.ind + 1) % self.slices
else:
self.ind = (self.ind - 1) % self.slices
self.update()
def update(self):
self.im.set_data(self.X[:, :, self.ind])
self.ax.set_ylabel('slice %s' % self.ind)
self.im.axes.figure.canvas.draw_idle()
def plot(X):
mpl.rc('image', cmap='gray')
fig, ax = plt.subplots(1, 1)
plot = IndexTracker(ax, X)
fig.canvas.mpl_connect('scroll_event', plot.scroll)
plt.show()
On VS Code, using the,
%matplotlib widget
backend, I call the following function in a new code cell:
X = np.random.rand(20, 20, 40)
plot(X)
I am able to successfully generate an interactive plot in an iPython notebook, whereby scrolling over the figure scrolls through the "image slices". The scroll event only works if I hover the cursor over the plot/figure (as it should), however the entire notebook scrolls as well, thereby moving the cursor out of the figure frame.
Is there a way to prevent the notebook from scrolling when the cursor is hovering over a figure in the cell output?

Pytorch Problem: My jupyter stuck when num_workers > 0

This is a snippet of my code in PyTorch, my jupiter notebook stuck when I used num_workers > 0, I spent a lot on this problem without any answer. I do not have a GPU and I work only with a CPU.
class IndexedDataset(Dataset):
def __init__(self,data,targets, test=False):
self.dataset = data
if not test:
self.labels = targets.numpy()
self.mask = np.concatenate((np.zeros(NUM_LABELED), np.ones(NUM_UNLABELED)))
def __len__(self):
return len(self.dataset)
def __getitem__(self, idx):
image = self.dataset[idx]
return image, self.labels[idx]
def display(self, idx):
plt.imshow(self.dataset[idx], cmap='gray')
plt.show()
train_set = IndexedDataset(train_data, train_target, test = False)
test_set = IndexedDataset(test_data, test_target, test = True)
train_loader = DataLoader(train_set, batch_size=BATCH_SIZE, num_workers=2)
test_loader = DataLoader(test_set, batch_size=BATCH_SIZE, num_workers=2)
Any help, appreciated.
When num_workers is greater than 0, PyTorch uses multiple processes for data loading.
Jupyter notebooks have known issues with multiprocessing.
One way to resolve this is not to use Jupyter notebooks - just write a normal .py file and run it via command-line.
Or try use what's suggested here: Jupyter notebook never finishes processing using multiprocessing (Python 3).
Since jupyter Notebook doesn't support python multiprocessing, there are two thin libraries, you should install one of them as mentioned here 1 and 2.
I prefer to solve my problem in two ways without using any external libraries:
By converting my file from .ipynb format to .py format and run it in the terminal and I write my code in the main() function as follows:
...
...
train_set = IndexedDataset(train_data, train_target, test = False)
train_loader = DataLoader(train_set, batch_size=BATCH_SIZE, num_workers=4)
if `__name__ == '__main__'`:
for images,label in train_loader:
print(images.shape)
With multiprocessing library as follows:
In try.ipynb:
import multiprocessing as mp
import processing as ps
...
...
train_set = IndexedDataset(train_data, train_target, test = False)
train_loader = DataLoader(train_set, batch_size=BATCH_SIZE)
if __name__=="__main__":
p = mp.Pool(8)
r = p.map(ps.getShape,train_loader)
print(r)
p.close()
In processing.py file:
def getShape(data):
for i in data:
return i[0].shape

Define the conditional Jupyter cell

I have Jupyter Notebook tutorials that I used Matplotlibe and ipywidgets(interact) to display video with NumPy 3D format.
class JupyterDisplay():
def __init__(self, video, median_filter_flag=False, color='gray', imgSizex=5, imgSizey=5, IntSlider_width='500px'):
self.color = color
self.video = video
self.imgSizex = imgSizex
self.imgSizey = imgSizey
self.median_filter_flag = median_filter_flag
interact(self.display, frame=widgets.IntSlider(min=0, max=self.video.shape[0] - 1, step=1, value=10,
layout=Layout(width=IntSlider_width),
readout_format='10', continuous_update=False,
description='Frame:'))
def display(self, frame):
fig = plt.figure(figsize=(self.imgSizex, self.imgSizey))
ax = fig.add_axes([0, 0, 1, 1])
if self.median_filter_flag:
frame_v = median_filter(self.video[int(frame), :, :], 3)
else:
frame_v = self.video[int(frame), :, :]
myplot = ax.imshow(frame_v, cmap=self.color)
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)
plt.colorbar(myplot, cax=cax)
plt.show()
I want to create an HTML version from tutorials with sphinx make HTML. But the video is not visualized in the HTML version. What is the best way to display dynamic video in the HTML version?
I can create the mp4 from videos, but in this case, I need to have a conditional Jupyter cell to only run this part of the code when making HTML Sphinx used. Can you inform me how I should define this conditional cell?

bokeh selected.on_change not working for my current setup

Basically, this is an interactive heatmap but the twist is that the source is updated by reading values from a file that gets updated regularly.
dont bother about the class "generator", it is just for keeping data and it runs regularly threaded
make sure a file named "Server_dump.txt" exists in the same directory of the script with a single number greater than 0 inside before u execute the bokeh script.
what basically happens is i change a number inside the file named "Server_dump.txt" by using echo 4 > Server_dump.txt on bash,
u can put any number other than 4 and the script automatically checks the file and plots the new point.
if u don't use bash, u could use a text editor , replace the number and save, and all will be the same.
the run function inside the generator class is the one which checks if this file was modified , reads the number, transforms it into x& y coords and increments the number of taps associated with these coords and gives the source x,y,taps values based on that number.
well that function works fine and each time i echo a number , the correct rectangle is plotted but,
now I want to add the functionality of that clicking on a certain rectangle triggers a callback to plot a second graph based on the coords of the clicked rectangle but i can't even get it to trigger even though i have tried other examples with selected.on_change in them and they worked fine.
*if i increase self.taps for a certain rect by writing the number to the file multiple times, color gets updated but if i hover over the rect it shows me the past values and not the latest value only .
my bokeh version is 1.0.4
from functools import partial
from random import random,randint
import threading
import time
from tornado import gen
from os.path import getmtime
from math import pi
import pandas as pd
from random import randint, random
from bokeh.io import show
from bokeh.models import LinearColorMapper, BasicTicker, widgets, PrintfTickFormatter, ColorBar, ColumnDataSource, FactorRange
from bokeh.plotting import figure, curdoc
from bokeh.layouts import row, column, gridplot
source = ColumnDataSource(data=dict(x=[], y=[], taps=[]))
doc = curdoc()
#sloppy data receiving function to change data to a plottable shape
class generator(threading.Thread):
def __init__(self):
super(generator, self).__init__()
self.chart_coords = {'x':[],'y':[],'taps':[]}
self.Pi_coords = {}
self.coord = 0
self.pos = 0
self.col = 0
self.row = 0
self.s = 0
self.t = 0
def chart_dict_gen(self,row, col):
self.col = col
self.row = row+1
self.chart_coords['x'] = [i for i in range(1,cla.row)]
self.chart_coords['y'] = [i for i in range(cla.col, 0, -1)] #reversed list because chart requires that
self.chart_coords['taps']= [0]*(row * col)
self.taps = [[0 for y in range(col)] for x in range(row)]
def Pi_dict_gen(self,row,col):
key = 1
for x in range(1,row):
for y in range(1,col):
self.Pi_coords[key] = (x,y)
key = key + 1
def Pi_to_chart(self,N):
x,y = self.Pi_coords[N][0], self.Pi_coords[N][1]
return x,y
def run(self):
while True:
if(self.t == 0):
self.t=1
continue
time.sleep(0.1)
h = getmtime("Server_dump.txt")
if self.s != h:
self.s = h
with open('Server_dump.txt') as f:
m = next(f)
y,x = self.Pi_to_chart(int(m))
self.taps[x][y] += 1
# but update the document from callback
doc.add_next_tick_callback(partial(update, x=x, y=y, taps=self.taps[x][y]))
cla = generator()
cla.chart_dict_gen(15,15)
cla.Pi_dict_gen(15, 15)
x = cla.chart_coords['x']
y = cla.chart_coords['y']
taps = cla.chart_coords['taps']
#gen.coroutine
def update(x, y, taps):
taps += taps
print(x,y,taps)
source.stream(dict(x=[x], y=[y], taps=[taps]))
colors = ["#CCEBFF","#B2E0FF","#99D6FF","#80CCFF","#66c2FF","#4DB8FF","#33ADFF","#19A3FF", "#0099FF", "#008AE6", "#007ACC","#006BB2", "#005C99", "#004C80", "#003D66", "#002E4C", "#001F33", "#000F1A", "#000000"]
mapper = LinearColorMapper(palette=colors, low= 0, high= 15) #low = min(cla.chart_coords['taps']) high = max(cla.chart_coords['taps'])
TOOLS = "hover,save,pan,box_zoom,reset,wheel_zoom"
p = figure(title="Tou",
x_range=list(map(str,x)),
y_range=list(map(str,reversed(y))),
x_axis_location="above",
plot_width=900, plot_height=400,
tools=TOOLS, toolbar_location='below',
tooltips=[('coords', '#y #x'), ('taps', '#taps%')])
p.grid.grid_line_color = "#ffffff"
p.axis.axis_line_color = "#ef4723"
p.axis.major_tick_line_color = "#af0a36"
p.axis.major_label_text_font_size = "7pt"
p.xgrid.grid_line_color = None
p.ygrid.grid_line_color = None
p.rect(x="x", y="y",
width=0.9, height=0.9,
source=source,
fill_color={'field': 'taps', 'transform': mapper},
line_color = "#ffffff",
)
color_bar = ColorBar(color_mapper=mapper,
major_label_text_font_size="7pt",
ticker=BasicTicker(desired_num_ticks=len(colors)),
formatter=PrintfTickFormatter(format="%d%%"),
label_standoff=6, border_line_color=None, location=(0, 0))
curdoc().theme = 'dark_minimal'
def ck(attr, old, new):
print('here') #doesn't even print hi in the terminal if i click anywhere
source.selected.on_change('indices', ck)
p.add_layout(color_bar, 'right')
doc.add_root(p)
thread = cla
thread.start()
i wanted even to get a printed hi in the terminal but nothing
You have not actually added any selection tool at all to your plot, so no selection is ever made. You have specified:
TOOLS = "hover,save,pan,box_zoom,reset,wheel_zoom"
Those are the only tools that will be added, and none of them make selections, there for nothing will cause source.selection.indices to ever be updated. If you are looking for selections based on tap, you must add a TapTool, e.g. with
TOOLS = "hover,save,pan,box_zoom,reset,wheel_zoom,tap"
Note that there will not be repeated callbacks if you tap the same rect multiple times. The callback only fires when the selection changes and clicking the same glyph twice in a row results in an identical selection.

How to update plotly plot in offline mode (Jupyter notebook)

I would like to build a simple interface with plotly and ipywidgets inside Jupyter Notebook (offline mode) and I am wondering how to update the plot if I want to add extra data. Here is my code:
import plotly
from plotly.offline import iplot
from plotly.graph_objs import graph_objs as go
import ipywidgets as widgets
from IPython.display import display
plotly.offline.init_notebook_mode(connected=True)
trace_high = go.Scatter(
x=[1,2,3,4],
y=[4,6,2,8],
name = "High",
line = dict(color = '#7F7F7F'),
opacity = 0.8)
data = [trace_high]
def plot_extra_data(drop):
if drop["new"] == "2":
trace_low = go.Scatter(
x=[1,2,3,4],
y=[1,7,3,5],
name = "Low",
line = dict(color = 'green'),
opacity = 0.8)
data.append(trace_low)
fig.update(data=data)
drop = widgets.Dropdown(
options=['1', '2', '3'],
value='1',
description='Number:',
disabled=False,
)
drop.observe(plot_extra_data, "value")
display(drop)
fig = dict(data=data)
iplot(fig)
Any comments/suggestions are highly appreciated.
Crazy how everyone seem to be confused about interacting with offline plotly charts!
Still it is fairly simple taking benefit of property assignment (e.g. see this documentation although it is now partly deprecated).
The naive snippet example below updates a plotly.graph_objs.FigureWidget() as user interacts via a dropdown widget. In fact, the pandas.DataFrame() containing the xaxis and yaxis data of the chart is sliced along a Commodity dimension the user wants to display the line chart of.
The most tedious part probably is getting all additional library requirements set if you are using jupyterlab
import pandas as pd
import plotly.graph_objs as go
import ipywidgets as widgets
df = pd.DataFrame({'cmdty' : ['beans', 'beans', 'beans', 'corn', 'corn', 'corn'],
'month' : [1, 2, 3, 1, 2, 3],
'value' : [10.5, 3.5, 8.0, 5.0, 8.75, 5.75]})
items = df.cmdty.unique().tolist()
cmdty = widgets.Dropdown(options=items,
description='Commodity')
def response(change):
c = cmdty.value
df_tmp = df[df.cmdty == c]
x0 = df_tmp['month'] # Useless here as x is equal for the 2 commodities
x1 = df_tmp['value']
fig.data[0].x = x0 # Useless here as x is equal for the 2 commodities
fig.data[0].y = x1
fig = go.FigureWidget(data=[{'type' : 'scatter'}])
cmdty.observe(response, names='value')
display(widgets.VBox([cmdty, fig]))

Resources