VSCode notebook silently failing show(modify_doc) - python

When using the built-in Jupyter notebook editor in Visual Studio Code and using the show(modify_doc) way of plotting, the result is not displayed. Showing individual plots does work.
I tried Googling and reading through the documentation but I couldn't find a solution anywhere. Hopefully someone knows what is wrong here.
(Example taken from the Internet)
Importing necessary modules:
from bokeh.io import push_notebook, show, output_notebook
from bokeh.layouts import row, gridplot
from bokeh.plotting import figure, show, output_file, curdoc
from bokeh.document import Document
output_notebook()
import numpy as np
This does not work as intended in VSCode but it does in the official Jupyter Notebook. I added a print statement as a test and it also does not get printed in VSCode.
def modify_doc(doc):
print("Test")
x = np.linspace(0, 4*np.pi, 100)
y = np.sin(x)
TOOLS = "pan,wheel_zoom,box_zoom,reset,save,box_select"
p1 = figure(title="Legend Example", tools=TOOLS)
p1.circle(x, y, legend="sin(x)")
p1.circle(x, 2*y, legend="2*sin(x)", color="orange")
p1.circle(x, 3*y, legend="3*sin(x)", color="green")
# Add everything to the layout
layout = row(p1)
# Add the layout to curdoc
doc.add_root(layout)
show(modify_doc)
The following code does run:
x2 = np.linspace(0, 4*np.pi, 100)
y2 = np.sin(x2)
TOOLS2 = "pan,wheel_zoom,box_zoom,reset,save,box_select"
p2 = figure(title="Legend Example", tools=TOOLS2)
p2.circle(x2, y2, legend="sin(x)")
p2.circle(x2, 2*y2, legend="2*sin(x)", color="orange")
p2.circle(x2, 3*y2, legend="3*sin(x)", color="green")
show(p2)

I had a similar problem. For me it used to work to output the bokeh figure in a jupyter notebook cell with show() in VS Code. But suddenly it stopped working even though I didn't make changes to the code (or reverted the changes to be more precise).
I could resolve the issue by changing the Anaconda environment to another environment and then switching back to the proper environment (see screenshot below).

Related

Interactive graphical visualization with matplotlib

I want to show specific data (not the columns I used in plotting my scatter plot but other columns in the dataframe) whenever I hover my mouse on each data point using matpotlib. I don't want to use plotly because I need to implement another part of matplotlib.
I wrote the following script but it is not implementing the hovering part when I run it in my jupyter notebook.
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
%matplotlib widget
# Load sample data
diamonds = sns.load_dataset('diamonds')
# Create a scatter plot with hue and use matplotlib to display the specific column values when hovering over a datapoint
sns.scatterplot(x="carat", y="price", hue="cut", data=diamonds)
def hover(event):
# Get the current mouse position
ax = event.inaxes
x, y = event.xdata, event.ydata
# Find the nearest datapoint
distances = ((diamonds['carat'] - x)**2 + (diamonds['price'] - y)**2)
idx = distances.idxmin()
# Display the specific column values in a pop-up window
text = f"Cut: {diamonds.loc[idx, 'cut']}\n" \
f"Clarity: {diamonds.loc[idx, 'clarity']}\n" \
f"Color: {diamonds.loc[idx, 'color']}"
plt.gcf().text(x, y, text, ha='left', va='bottom', fontsize=10, backgroundcolor='white', alpha=0.7)
# Connect the hover function to the figure
fig = plt.gcf()
fig.canvas.mpl_connect("motion_notify_event", hover)
# Show the plot
plt.show()
This is easier with mplcursors. There's a similar example of extracting the data and labels for the annotation from a dataframe to plug into. Implemented with your example it is:
%matplotlib ipympl
# based on https://mplcursors.readthedocs.io/en/stable/examples/dataframe.html
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
from matplotlib.patheffects import withSimplePatchShadow
import mplcursors
df = sns.load_dataset('diamonds')[:10]
sbsp = sns.scatterplot(x="carat", y="price", hue="cut", data=df)
def show_hover_panel(get_text_func=None):
cursor = mplcursors.cursor(
hover=2, # Transient
annotation_kwargs=dict(
bbox=dict(
boxstyle="square,pad=0.5",
facecolor="wheat",
edgecolor="#ddd",
linewidth=0.5,
path_effects=[withSimplePatchShadow(offset=(1.5, -1.5))],
),
linespacing=1.5,
arrowprops=None,
),
highlight=True,
highlight_kwargs=dict(linewidth=2),
)
if get_text_func:
cursor.connect(
event="add",
func=lambda sel: sel.annotation.set_text(get_text_func(sel.index)),
)
return cursor
def on_add(index):
item = df.iloc[index]
parts = [
f"Cut: {item.cut}", # f"Cut: {diamonds.loc[idx, 'cut']}\n"
f"Clarity: {item.clarity}", # f"Clarity: {diamonds.loc[idx, 'clarity']}\n"
f"Color: {item.color}", #f"Color: {diamonds.loc[idx, 'color']}"
]
return "\n".join(parts)
sbsp.figure.canvas.header_visible = False # Hide the Figure name at the top of the figure;based on https://matplotlib.org/ipympl/examples/full-example.html
show_hover_panel(on_add)
plt.show();
That's for running it in JupyterLab where ipympl has been installed.
For running it in Jupyter Notebook at present, change the first line to %matplotlib notebook.
I saw it be smoother in JupyterLab.
I'll point to ways to try the code in both interfaces without installing anything on your system below.
(Your approach may be able to work with more incorporation of things here. However, there's already a very similar answer with mplcursors)
(The places and steps to run the code outlined below were worked out primarily for the Matplotlib option here yesterday. Noting that here as there were some quirks to the ipympl offering launching and I worry that I may miss updating each place if something changes.)
Try it in JupyterLab in conjunction with ipympl without touching your system
This will allow you to try the code in JupyterLab without installing anything on your own system.
Go to here. Sadly the link currently goes to a dead end and doesn't seem to build a new image right now. Fortunately, right now this offering works for launching.
When that session opens, run in a notebook %pip install mplcursors seaborn. Let that installation command run to install both mplcursors and seaborn and then restart the kernel.
Make a new cell and paste in the code from above and run it.
Try it Jupyter Notebook classic interface without touching your system
This will allow you to try the code in the present classic Jupyter Notebook interface (soon-to-be more-often-referenced as 'the document-centric interface' as the underlying machinery for Jupyter Notebook 7 will use JupyterLab components) without installing anything on your own system.
Go here and press 'launch binder'. A temporary, remote session will spin up served via MyBinder.
Make a new cell and simply add %matplotlib notebook at the top of the cell. Then add the code above to the cell, leaving off the first line of the suggested code, so that you effectively substitute %matplotlib notebook in place of %matplotlib ipympl.
Run the cell.

refresh matplotlib in Jupyter when updating with ipywidget

I want to draw a line in a Jupyter notebook, which can be moved using an ipywidget slider. I also want to have the mouse coordinates displayed, for which I'm using %matplotlib notebook. Here is what I have so far :
%matplotlib notebook
from ipywidgets import interact
fig, ax = plt.subplots()
#interact(n=(-200, 0))
def show(n):
# fig.clear() #doesn't show anything
y = -n+x
ax.plot(x, y)
plt.show()
When moving the line using the slider, the plot doesn't refresh, all previous positions of the line
remain visible:
I tried to refresh using fig.clear(), but then noting shows.
How can I solve this?
I have an extensive answer about this here: Matplotlib figure is not updating with ipywidgets slider
but the short of my recommendations are:
use ipympl %matplotlib ipympl instead of notebook as this will play nicer with ipywidgets
Use mpl-interactions to handle making plots controlled by sliders.
It will do the optimal thing of using set_data for you rather than clearing and replotting the lines.
It also interprets the shorthand for numbers in a way that (I think) makes more sense when making plots (e.g. using linspace instead of arange) see https://mpl-interactions.readthedocs.io/en/stable/comparison.html for more details.
So for your example I recommend doing:
install libraries
pip install ipympl mpl-interactions
%matplotlib ipympl
from ipywidgets import interact
import matplotlib.pyplot as plt
from mpl_interactions import ipyplot as iplt
x = np.linspace(0,100)
fig, ax = plt.subplots()
def y(x, n):
return x - n
ctrls = iplt.plot(x, y, n=(-200,0))
it got a bit longer because I added the imports you left out of your question and also defined x.
Which gives you this:
That said if you don't want to use those I think what you want is ax.cla() I think when you do fig.clear you are also removing the axes which is why nothing shows up.
%matplotlib notebook
from ipywidgets import interact
fig, ax = plt.subplots()
#interact(n=(-200, 0))
def show(n):
y = -n+x
ax.cla()
ax.plot(x, y)
plt.show()

bokeh, ipywidgets, jupyterlab and voilà

I'm trying to create a webapp using bokeh. Mostly, it will consist of markdown text and some figures. Right now I'm stuck a getting voilà to show two bokeh figures side by side. Within the notebook everything runs smoothly, but in the voilà visualization I see errors like
Javascript Error: Error rendering Bokeh model: could not find #5db0eeb2-830f-4e00-b6fe-552a45536513 HTML tag
Now, if I try in classic jupyter notebook (within jupyter-lab Help -> Launch Classic Notebook), then it renders fine. However, when it is served from github, I get again javascript errors.
A MWE within jupyterlab but non-working in voilà is:
import numpy as np
import ipywidgets as widgets
import bokeh.plotting
from bokeh.io import output_notebook, show
from bokeh.models import ColumnDataSource, Line
output_notebook()
t = np.arange(10)
signal = np.arange(10)
f_1 = bokeh.plotting.figure(plot_width=400, plot_height=300, toolbar_location=None)
data_source_1 = ColumnDataSource(data=dict(t=t, signal=signal))
f_1.line(x='t', y='signal', source=data_source_1)
out_1 = widgets.Output()
with out_1:
show(f_1)
f_2 = bokeh.plotting.figure(plot_width=400, plot_height=300, toolbar_location=None)
data_source_2 = ColumnDataSource(data=dict(t=t, signal=2*signal))
f_2.line(x='t', y='signal', source=data_source_2)
out_2 = widgets.Output()
with out_2:
show(f_2)
widgets.HBox([out_1, out_2])
This is meant to be part of mini-lecture on analog modulations: the classic notebook version works fine, but when I try to use voilà-served version (click the Voilà button there or just go to this other link) I hit the same problem.
Any clue?

widget for function input is not shown in nbviewer

I've written a python module and would like to make some of the functions available via a jupyter notebook. For this I would like to visualise (plot) the functions. The notebook should be interactive, i.e. the user can change inputs and gets the corresponding result / plot back.
I've tried to make a use case work as I've never used jupyter before. I followed this. Here is the code from their site:
%matplotlib inline
from ipywidgets import interact
import matplotlib.pyplot as plt
import numpy as np
def f(m, b):
plt.figure(2)
x = np.linspace(-10, 10, num=1000)
plt.plot(x, m * x + b)
plt.ylim(-5, 5)
plt.show()
interactive_plot = interactive(f, m=(-2.0, 2.0), b=(-3, 3, 0.5))
output = interactive_plot.children[-1]
output.layout.height = '350px'
interactive_plot
locally everything is working fine. As soon as I upload it to github and want to show it on nbviewer (can be found here) the interactive sliders don't work. What am I doing wrong?
Is there a restriction for this on the python version?

Adding clickable circle in bokeh plots

I am trying to add certain callbacks to a circles which are plotted on bokeh plot. Each circle is associated with certain record from columndatasource. I want to access that record whenever corresponding circle is clicked. Is there any way to add callbacks to circles in bokeh?
How can i do it?
I am using following code
fig =figure(x_range=(-bound, bound), y_range=(-bound, bound),
plot_width=800, plot_height=500,output_backend="webgl")
fig.circle(x='longitude',y='latitude',size=2,source=source,fill_color="blue",
fill_alpha=1, line_color=None)
Then you want to add an on_change callback to the selected property of the data source. Here is a minimal example. As stated above, python callbacks require the Bokeh server (that is where python callbacks actually get run, since the browser knows nothing of python), so this must be run e.g. bokeh serve --show example.py (Or, if you are in a notebook, following the pattern in this example notebook).
# example.py
from bokeh.io import curdoc
from bokeh.models import ColumnDataSource
from bokeh.plotting import figure
source = ColumnDataSource(data=dict(x=[1,2,3], y=[4,6,5]))
p = figure(title="select a circle", tools="tap")
p.circle('x', 'y', size=25, source=source)
def callback(attr, old, new):
# This uses syntax for Bokeh >= 0.13
print("Indices of selected circles: ", source.selected.indices)
source.selected.on_change('indices', callback)
curdoc().add_root(p)

Categories

Resources