Widgets run perfectly in Jupyter Notebook, but do nothing in Voila - jupyter-notebook

I have several buttons which generate images. All work perfectly in Jupyter Notebook, but when I click Voila, and click the buttons, nothing happens. The first button works, but the code is very similar to run other models, yet the other buttons do not work. Is there a work around for this issue?
Edit:
My code which does not show the output when the button is clicked:
compare = {}
button9 = widgets.Button(description = "Report All")
output = widgets.Output()
display(button9, output)
dt = DecisionTreeClassifier(random_state=42)
dt = dt.fit(X_train, y_train)
y_pred = dt.predict(X_test)
compare['Decision Trees'] = [accuracy_score(y_test, y_pred), precision_score(y_test, y_pred), recall_score(y_test, y_pred), f1_score(y_test, y_pred)]
def report_button(b):
compare = pd.DataFrame.from_dict(compare).T
compare.columns = ['Accuracy', 'Precision', 'Recall', 'F1 Score']
compare = com.sort_values('Accuracy', ascending=False)
sns.heatmap(compare, center = True, fmt='.4f', cmap='Blues', annot=True)
button9.on_click(report_button)
However this code displays the output when clicked:
button3 = widgets.Button(description="Decision Trees")
output3 = widgets.Output()
display(button3, output3)
def dt_button(b):
# Decision Trees Classifier
dt = DecisionTreeClassifier(random_state=42)
dt = dt.fit(X_train, y_train)
y_pred = dt.predict(X_test)
compare['Decision Trees'] = [accuracy_score(y_test, y_pred), precision_score(y_test, y_pred_dt), recall_score(y_test, y_pred), f1_score(y_test, y_pred)]
CM = confusion_matrix(y_test, y_pred_dt)
sns.heatmap(CM, center = True, fmt='', cmap='Blues', annot=True)
plt.title('Decision Trees Confusion Matrix')
plt.show()
button3.on_click(dt_button)
Additionally, I am having the issue of MyBinder rendering my file with Voila, but after a few minutes, the MyBinder link shows Error 404.

I'm answering your last question here (about the download button) because I need to add code blocks and comments don't allow that.
You are using Panel in your notebook to do the download and so it works. For Voila you need to stick with ipywidgets-compatible solutions as I discussed earlier. You cannot just add another dashboard extension, Panel, and expect it to work in Voila
Here makes it seem this isn't as easy as it seems.
Suggested Option:
Based on https://stackoverflow.com/a/60013735/8508004 , using SVM_Confusion_Matrix.jpg as the example.
%%html
Click to Download SVM image
Options along that line can even be coded to show up dynamically after an event in VOila, see example code use.
Not suggested but could be useful for similar:
Based on https://github.com/jupyter-widgets/ipywidgets/issues/2471#issuecomment-580965788 (this just opens the image as separate and you have to right-click and save image as)
from IPython.display import display, FileLink
local_file = FileLink('./SVM_Confusion_Matrix.jpg', result_html_prefix="Click here to download: ")
display(local_file)

Related

How to change plotly graph size in rmarkdown inline?

I would like to see bigger plotly graphs while doing EDA in R Markdown. If I change the graph size through plotly functions like ggplotly or plot_ly, RStudio creates scroll bars and wouldn't show more than 800px width.
Here is my code:
gg1 <- cars |>
ggplot(aes(speed, dist)) +
geom_point()
gg1 |>
plotly::ggplotly(width = 1000, height = 800)
This is what I see:
Things I tried but didn't do anything...
out.width
fig.width
RStudio Tools > Global Options > R Markdown > Visual > Editor content width (I don't know if this does anything)
Now, if I output to console instead of inline or knit to html, then the code prints out bigger graphic without any error. But I would like to see bigger graphics while in RStudio R Markdown interactive session inline.
I couldn't find a way that works as a setting in R or R Markdown. However, I can tell you how to set this temporarily.
You will use:
RStudio's developer tools (standard part of RStudio)
two sets of function calls written in Javascript
This is temporary. To reset the chunk outputs back to normal:
collapse the chunk
rerun the chunk
restart RStudio
If you add chunks after you run the functions, they will not inherit these changes. If want them to change, rerun the functions.
The first line of each set of functions is variable initialization. Skip that first line of code if you run the functions a second time (or more).
Here's what to do:
Anywhere in RStudio, right-click, select "Inspect Element"
This will open developer tools. In the developer tools window, open the console drawer. You can select the three dots on the top right and use the menu to do this.
In the console drawer, you will paste the functions I've provided. However, the calls for the variables can only be done one time. So the first time you run this in the same session of RStudio you will include that line, after that, do not. When you restart RStudio, this resets. You will need to include that line again. (If you restart developer tools, this will not reset these variables.)
The console is at the bottom of developer tools.
Here is the before...
Here's an example of a copy and paste, first time in the RStudio session.
You will immediately see that the width has changed for any chunks with output.
However, you may notice that the overflow is hidden. That's next.
You will enter the second function into the console drawer to fix change that.
It won't look different this time!
When you look at the chunk output, it will still look like content is hidden.
From here you have to drag the panes, to force resizing. Make it bigger, smaller, or even return to the size you had to begin with. The overflow will be shown.
Last, but certainly not least--the Javascript functions.
The first:
//declare variables separately for reuse without duplicate initialization errors
var allOf, sAdd, styler, i, n;
allOf = document.querySelectorAll('[data-ordinal]'); //find them all
if (allOf==undefined || allOf==null) {
allOf = document.querySelector('[data-ordinal]'); // if there is only one
}
sAdd = "max-width: none;" // create style to add
try{
for(i = 0, n = allOf.length; i < n; i++){ //loop through them all
styler = allOf[i].getAttribute("style");
if (styler==undefined || styler==null) { // if there are no HTML styles set
styler = "";
console.log("No style attributes found for ", i)
}
if (styler!="width: 100%; max-width: 800px;") { // if this isn't a chunk output as expected
continue;
console.log("Attributes not changed for ", i)
}
allOf[i].setAttribute("style",styler+sAdd); // append style
console.log("Attributes set for ", i);
}} catch(error) {
console.error(error);
}
The second:
//declare variables separately for reuse without duplicate initialization errors
var allMore, sAdd2, styler2, j, m
allMore = document.querySelectorAll('.ace_lineWidgetContainer > div'); // first child of class
if (allMore==undefined || allMore==null) {
allMore = document.querySelector('.ace_lineWidgetContainer > div'); // if there is only one
}
sAdd2 = "overflow: visible;" // create style to add
try{
for(j = 0, m = allMore.length; j < m; j++){ //loop through them all
styler2 = allMore[j].getAttribute("style");
if (styler2==undefined || styler2==null) { // if there are no HTML styles set
styler2 = "";
console.log("No styles were found for ", j)
}
allMore[j].setAttribute("style",styler2+sAdd2); // append new styles
allMore[j].style.height = null; // remove the height style
console.log("Attributes set for ", j);
}} catch(error) {
console.error(error);
}
You do not have to use these in a specific order. However, other than that first line (variable initialization), you need to run all of the lines together if you run them at all.
If something goes wrong or RStudio becomes some mutant version of itself, just restart RStudio to reset back to the original sizing.

R/exams d2l multiple choice question doesn't select correct answer

I use the following to create a D2L exam from the "capital.Rmd" example (I converted the question to schoice)
exams2blackboard("capitals.Rmd", n =3, name = "testquiz" )
After I upload the testquiz.zip file, I notice that the correct answer must be manually chosen on the D2L platform.
I was wondering if there is a workaround.
Many Thanks,
Umut
If you want the correct solution to be selected, do not use the Import option from the Question Library or from the Quiz itself. Use the Import/Export/Copy Components under the Course Admin tab.
If you import the questions through the following steps, BrightSpace correctly picks the right solution. It’s a bit longer but seems to correctly choose the solution.
Under the Course Admin tab of your course, go to
'Import/Export/Copy Components' -> ‘Import Components’ -> Start -> (drag and drop the ZIP file)
Click ‘Advanced Options…’
This step will take a few minutes for large files; if you do not click
Advanced Options, then the import will automatically import the
questions into the 'Question Library' and will generate a Quiz with the
imported questions; you do not want this.
-> Continue -> Continue -> at this point choose 'Question Library' from the section 'Select Components to Import'
I would not choose ‘Quizzes’ because it automatically creates a quiz
and makes it available to students. It has the unfortunate side-effect
of making ALL the questions available, which means all the versions of
various dynamic questions; this is not something we want.
-> Continue -> Continue. This stage takes a few minutes for large
imports.
Now the Questions are available in the Question Library and can be used to generate new quizzes. Each question has the correct answer selected already. This works for ‘schoice’ and ‘mchoice’ versions of questions. Currently, plots are not imported, though, still trying to figure out why.
This problem is new to me. In earlier versions of Brightspace/D2L the import of single-choice and multiple-choice exercises via exams2blackboard() worked well. Possibly, D2L changed in the meantime given that neither the current release version from CRAN nor the development version from R-Forge work for you.
D2L also supports other import formats and we did play around with some of these. See the following discussions in the R/exams forum on R-Forge:
https://R-Forge.R-project.org/forum/forum.php?thread_id=33404&forum_id=4377&group_id=1337
https://R-Forge.R-project.org/forum/forum.php?thread_id=33657&forum_id=4377&group_id=1337
Notably we tried to use the XML-based QTI 2.1 format that seems to be employed by D2L internally. However, D2L apparently uses a particular custom flavor of QTI 2.1. It should be possible to reverse engineer that and improve exams2qti21() correspondingly but so far (to the best of my knowledge) no one put the time and effort into this that would be needed.
For simple single/multiple choice questions a CSV-based exchange format can also be used. I have put together a very basic exams2d2l() function that was posted in the threads above and that I'm also including below. It can set up the CSV file for a single exercise like the capitals.Rmd exercise that you use above. For plain text exercises like that it seems to work well but not for more complex elements (graphics, code, math, etc.).
exams2d2l <- function(file, dir = ".", ## n = 1L, nsamp = NULL disabled for now
name = NULL, quiet = TRUE, edir = NULL, tdir = NULL, sdir = NULL, verbose = FALSE,
resolution = 100, width = 4, height = 4, svg = FALSE,
encoding = "", converter = NULL, ...)
{
## for Rnw exercises use "ttm" converter otherwise "pandoc" converter
if(any(tolower(tools::file_ext(unlist(file))) == "rmd")) {
if(is.null(converter)) converter <- "pandoc"
} else {
if(is.null(converter)) converter <- "ttm"
}
## output directory or display on the fly
## output name processing
if(is.null(name)) name <- tools::file_path_sans_ext(basename(file))
## set up .html transformer and writer function
htmltransform <- make_exercise_transform_html(converter = converter, ...)
## create exam with HTML text
rval <- xexams(file,
driver = list(sweave = list(quiet = quiet, pdf = FALSE, png = !svg, svg = svg,
resolution = resolution, width = width, height = height, encoding = encoding),
read = NULL, transform = htmltransform, write = NULL),
dir = dir, edir = edir, tdir = tdir, sdir = sdir, verbose = verbose)
## currently: only a single exercise
rval <- rval[[1L]][[1L]]
## put together CSV
cleanup <- function(x) gsub('"', '""', paste(x, collapse = "\n"), fixed = TRUE)
rval <- c(
'NewQuestion,MC,,,',
sprintf('ID,"%s",,,', cleanup(rval$metainfo$file)),
sprintf('Title,"%s",,,', cleanup(rval$metainfo$name)),
sprintf('QuestionText,"%s",,,', cleanup(rval$question)),
sprintf('Points,%s,,,', if(is.null(rval$metainfo$points)) 1 else rval$metainfo$points),
'Difficulty,1,,,',
'Image,,,,',
paste0('Option,', ifelse(rval$metainfo$solution, 100, 0), ',"', cleanup(rval$questionlist), '",,"', cleanup(rval$solutionlist), '"'),
'Hint,,,,',
sprintf('Feedback,"%s",,,', cleanup(rval$solution))
)
writeLines(rval, file.path(dir, paste0(name, ".csv")))
invisible(rval)
}

use ipywidget interactive() with option manual=True

I am updating a jupyter notebooks with interactive widgets to a more recent version (ipywidgets 7.2.1).
It used to have interactive() functions that were executed manually by clicking on a button (feature __manual=True). However now I cannot reproduce the same behavior.
Here is a minimal example:
from ipywidgets import interactive, interact_manual
import ipywidgets as widgets
def do_sth(x):
#do sth with the argument passed
print("done "+str(x))
nb = widgets.BoundedIntText(description='Number:')
#Interaction in accordion nested in a tab
tab = widgets.Tab()
tab.set_title(0, 'Page 1')
#old method
#problem: it is not manual anymore
w = interactive(do_sth, x=nb, __manual=True)
#new solution 1
#problem: the widget appears also outside the tab/accordion
w1 = interact_manual(do_sth, x=nb)
w1.widget.children[1].description = 'do sth' #seems a bit of a hack
#new solution 2
w2 = interactive(do_sth, x=nb, manual=True) #does no pass the manual option
#if I set it manually with:
#w2.manual = True
#It generates an error (AttributeError: 'interactive' object has no attribute 'manual_button')
accordion = widgets.Accordion(children=[w, w1.widget, w2])
accordion.set_title(0, 'old interaction 0')
accordion.set_title(1, 'new interaction 1')
accordion.set_title(2, 'new interaction 2')
tab.children = [accordion]
tab
Is it possible to use solution 1 and prevent the widget from appearing twice? Otherwise, is there another way to do this?
Seems they may have moved it into a dict when adding the ability to relabel the button.
Try
w2 = interactive(do_sth, {'manual' : True, 'manual_name' : 'Do Something'}, x=nb)

Most efficient way of displaying jpgs with bokeh? Image_rgba surprisingly slow

I've tried using the bokeh image_rgba method but found it to be very slow, I'm just displaying a 1000*500 px image and the html takes ~5 seconds to load (nothing is web based here, I have everything running/stored locally)
Again the code itself runs fast, itùs just displaying the image thqt is slow. I've been trying exqmples from the bokeh gallery and the speed is fine.
I'm thus wondering if there is anything I could do for the html to load faster? Is image_rgba the best way to go to display an image with bokeh?
This is the code I use:
pic = PIL.Image.open('/Users/blabla/eiffelTower.jpg')
self.imgArray = np.array(pic)
N1 = imgArray.shape[0]
N2 = imgArray.shape[1]
img = np.zeros((N1,prolongatedN2), dtype=np.uint32)
view = img.view(dtype=np.uint8).reshape((N1, N2, 4))
view[:N1,:N2,0] = self.imgArray[range(N1-1,-1,-1),:N2,0]
view[:N1,:N2,1] = self.imgArray[range(N1-1,-1,-1),:N2,1]
view[:N1,:N2,2] = self.imgArray[range(N1-1,-1,-1),:N2,2]
fig = bokeh.plotting.figure(plot_width = plot_width, plot_height=plot_height)
fig.image_rgba(image=[img], x=[0], y=[0],
dw=[plot_width], dh=[plot_height])
script, div = bokeh.embed.components(p.fig, INLINE)
output_file('testBokeh.html')
show(fig)
Again I'm quite surprised that displaying a locally stored 1000*500 pixels would be so slow.
FWIW, I do this, and it's very fast.
from __future__ import division
import numpy as np
from PIL import Image
from bokeh.plotting import figure, show, output_file
# Open image, and make sure it's RGB*A*
lena_img = Image.open('Lenna_rect.png').convert('RGBA')
xdim, ydim = lena_img.size
print("Dimensions: ({xdim}, {ydim})".format(**locals()))
# Create an array representation for the image `img`, and an 8-bit "4
# layer/RGBA" version of it `view`.
img = np.empty((ydim, xdim), dtype=np.uint32)
view = img.view(dtype=np.uint8).reshape((ydim, xdim, 4))
# Copy the RGBA image into view, flipping it so it comes right-side up
# with a lower-left origin
view[:,:,:] = np.flipud(np.asarray(lena_img))
# Display the 32-bit RGBA image
dim = max(xdim, ydim)
fig = figure(title="Lena",
x_range=(0,dim), y_range=(0,dim),
# Specifying xdim/ydim isn't quire right :-(
# width=xdim, height=ydim,
)
fig.image_rgba(image=[img], x=0, y=0, dw=xdim, dh=ydim)
output_file("lena.html", title="image example")
show(fig) # open a browser

iPython Notebook not embedding animations

I've been trying to embed an animation into an iPython notebook but without success. I'm using the latest version of Enthought Canopy (python 2.7.3) on a Mac running 10.8.5 using Safari as my default browser.
After much failed experimentation, I tried using this code
%pylab inline
from tempfile import NamedTemporaryFile
VIDEO_TAG = """<video controls>
<source src="data:video/x-m4v;base64,{0}" type="video/mp4">
Your browser does not support the video tag.
</video>"""
def anim_to_html(anim):
if not hasattr(anim, '_encoded_video'):
with NamedTemporaryFile(suffix='.mp4') as f:
anim.save(f.name, fps=20, extra_args=['-vcodec', 'libx264'])
video = open(f.name, "rb").read()
anim._encoded_video = video.encode("base64")
return VIDEO_TAG.format(anim._encoded_video)
from IPython.display import HTML
def display_animation(anim):
plt.close(anim._fig)
return HTML(anim_to_html(anim))
from matplotlib import animation
# First set up the figure, the axis, and the plot element we want to animate
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [], lw=2)
# initialization function: plot the background of each frame
def init():
line.set_data([], [])
return line,
# animation function. This is called sequentially
def animate(i):
x = np.linspace(0, 2, 1000)
y = np.sin(2 * np.pi * (x - 0.01 * i))
line.set_data(x, y)
return line,
# call the animator. blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=100, interval=20, blit=True)
# call our new function to display the animation
display_animation(anim)
from jake Vanderplas on the web. I installed ffmpeg.
On running the code I get the video progress bar, but no graph, just an empty space above the video progress bar.
After a couple of days of working on this I've not found a solution (the above is the closest I've come to). Can anyone see what's going wrong or suggestions to try?
Many thanks.
This problem is solved in Jessica Hamrick's comment on Jake Vanderplas's blog at https://jakevdp.github.io/blog/2013/05/12/embedding-matplotlib-animations/
She added added two additional items to the extra_args argument:
extra_args=['-vcodec', 'libx264', '-pix_fmt', 'yuv420p']

Resources