Passing variable to python from JS not working in Bokeh - jupyter-notebook

This issue is breaking my mind
I cannot pass simple variable to python from JS in Bokeh.
So, something like this is working fine:
from IPython.display import HTML
input_form = """
<div style="background-color:gainsboro; border:solid black; width:300px; padding:20px;">
Variable Name: <input type="text" id="var_name" value="foo"><br>
Variable Value: <input type="text" id="var_value" value="bar"><br>
<button onclick="set_value()">Set Value</button>
</div>
"""
javascript = """
<script type="text/Javascript">
function set_value(){
var var_name = document.getElementById('var_name').value;
var var_value = document.getElementById('var_value').value;
var command = var_name + " = '" + var_value + "'";
console.log("Executing Command: " + command);
var kernel = IPython.notebook.kernel;
kernel.execute(command);
}
</script>
"""
HTML(input_form + javascript)
While this code from Bokeh is not working!!!
Python keeps returning "name 'inds' is not defined"
source.callback = CustomJS(args=dict(p=p), code="""
var inds = cb_obj.get('selected')['1d'].indices;
var d1 = cb_obj.get('data');
console.log(d1)
var kernel = IPython.notebook.kernel;
IPython.notebook.kernel.execute("inds = " + inds); """)
Any help?

Related

Making a button that shows or hides multiple images in a random location

I have a problem when I am making the website for one gallery.
I made the code for the button that can show and hide multiple images.
I intend to make the button can place several images in randomly.
I write the code that can function for only one image.
Please tell me the code that functions as a button to place multiple images in a random location.
Users can hide images by pressing the button.
And when users press the button again, it places the images in another random location.
const btn = document.querySelector("button");
const height = document.documentElement.clientHeight;
const width = document.documentElement.clientWidth;
const box = document.getElementById("color");
btn.addEventListener("click", () => {
let randY = Math.floor((Math.random() * height) + 1);
let randX = Math.floor((Math.random() * width) + 1);
box.style.top = randY + "px";
box.style.right = randX + "px";
});
function showhide() {
var x = document.querySelectorAll("#color");
var i;
for (i = 0; i < x.length; i++) {
if (x[i].style.display === "block") {
x[i].style.display = "none";
} else {
x[i].style.display =
"block";
}
}
}
body {
height: 500px;
}
.random {
position: absolute;
}
<button onclick="showhide()" value="Zeige Features" id="button">click me</button>
<img id="color" style="display: none;" class="random" src="http://lorempixel.com/200/200/">
<img id="color" style="display: none;" class="random" src="http://lorempixel.com/200/200/">
You're doing the correct thing in showHide() when using querySelectorAll. You are then able to get all images.
You should never have elements with the same ids. They should be unique. So querySelectorAll("#color") works, but it's now how you should do. Do a querySelector on "img.random" instead.
getElementById only returns a single element, not like querySelectorAll. So you need to use querySelectorAll('img.random').
This might be beyond your knowledge, I don't think you should add the images in HTML, but in javascript code.
a) Add all image paths in an array: ['https://image.com/image.png', ...]
b) Add a single img element. <img id="template" class="random">
c) In javascript code, clone that element for each image path in the array. You can use cloneNode for this.
d) Randomize each position for each element, just like you have done now.
e) Add each element to the DOM through appendChild. Have a unique div that you append to. Be sure to clear it every time second time you hit the button.
f) Solve all bugs along the way. :P
The problem
The main issue here is that you're using getElementById to query #color
const box = document.getElementById("color");
Since getElementById only returns one element (but you have two in your DOM) and the style only applies to one element. That's why you're seeing only one element is randomly moving and the other just stay in the same place.
A side note here, id should be unique in a DOM.
You're in fact using the correct API for the job in the showhide function
var x = document.querySelectorAll("#color");
The fix:
To fix this, you need to query all images by their classname (as suggested in the side note, don't use id for the job)
const boxes = document.querySelectorAll(".random");
Now we have a node list, as you do in the showhide function, we need to loop thru it, I'm not using a for loop here, instead, a forEach loop, it's just more terser and a modern addition to the JS
// Since boxes are not array, we need to covert it to array so we can use that handy `.forEach` here:
Array.from(boxes).forEach(box => {
box.style.top = Math.floor((Math.random() * height) + 1) + "px";
box.style.right = Math.floor((Math.random() * width) + 1) + "px";
})
Now, this should fix your issue. See the complete code below.
const btn = document.querySelector("button");
const height = document.documentElement.clientHeight;
const width = document.documentElement.clientWidth;
const boxes = document.querySelectorAll(".random");
btn.addEventListener("click", () => {
Array.from(boxes).forEach(box => {
box.style.top = Math.floor((Math.random() * height) + 1) + "px";
box.style.right = Math.floor((Math.random() * width) + 1) + "px";
})
});
function showhide() {
var x = document.querySelectorAll(".random");
var i;
for (i = 0; i < x.length; i++) {
if (x[i].style.display === "block") {
x[i].style.display = "none";
} else {
x[i].style.display =
"block";
}
}
}
body {
height: 500px;
}
.random {
position: absolute;
}
<button onclick="showhide()" value="Zeige Features" id="button">click me</button>
<img id="color" style="display: none;" class="random" src="http://lorempixel.com/200/200/">
<img id="color" style="display: none;" class="random" src="http://lorempixel.com/100/100/">

Center Typeform Popup Button in Squarespace

Embedding my Typeform on my Squarespace website Contact Page, as "Popup", not "Right Drawer" or "Left Drawer", but I cannot get it to center. It aligns to the left. Any ideas? Thanks!
Here's my code:
<a class="typeform-share button" href="https://artisan82interiors.typeform.com/to/KAh3xu" data-mode="popup" style="display:inline-block;text-decoration:none;background-color:#267DDD;color:white;cursor:pointer;font-family:Helvetica,Arial,sans-serif;font-size:20px;line-height:50px;text-align:center;margin:0;height:50px;padding:0px 33px;border-radius:25px;max-width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-weight:bold;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;"
data-submit-close-delay="3" target="_blank">Launch me </a>
<script>
(function() {
var qs, js, q, s, d = document,
gi = d.getElementById,
ce = d.createElement,
gt = d.getElementsByTagName,
id = "typef_orm_share",
b = "https://embed.typeform.com/";
if (!gi.call(d, id)) {
js = ce.call(d, "script");
js.id = id;
js.src = b + "embed.js";
q = gt.call(d, "script")[0];
q.parentNode.insertBefore(js, q)
}
})()
</script>
I just experienced the same issue, and found a workaround, so sharing it in case it helps you (or anyone else reading).
Embed the Typeform using a code block, and wrap the Typeform code in like so:
<center> [Your Typeform code] </center>

Getting invalid format response in R when using sprintf - invalid format '% he'

I'm trying to dynamically build an html file and one of the variables will depend on the number of files in a directory that match a pattern. Here is the code:
html <- '
<!DOCTYPE HTML>
<html>
<head>
<meta charset = "utf-8">
<title>Sankey Plot Test</title>
<script type = "text/javascript" src = "http://code.jquery.com/jquery-latest.min.js"></script>
</head>
<body>
<iframe src = "plot0.html" width = 100% height = 1000px id = "sankey" style = "border: none"></iframe>
<script>
$(function() {
var selector = $("#sankey");
var delay_sec = 1;
var num = 1,
len = %d;
setInterval(function() {
num = (num === len) ? 0 : num;
selector.attr("src", "plot" + num + ".html");
num++;
}, delay_sec * 1000);
});
</script>
</body>
</html>'
n <- list.files(path = "path/to/files", pattern = "plot\\d+.html") %>% length()
html <- sprintf(html, n)
It's returning an error saying that the format is incorrect for my integer object, despite using %d. I saw a couple other questions on SO that mentioned incorrect format errors when using %d with sprintf, but none like what I'm seeing.
Any insight about what's going on would be appreciated. Thanks!
Your problem is in this line:
<iframe src = "plot0.html" width = 100% height
Notice the %. You can escape the % with another % like this:
<iframe src = "plot0.html" width = 100%% height
When sprintf runs through the string it will output the 100% correctly.

Creating a button for Leaflet JS "panTo spot on map" outside of the map in Meteor

I have created a map in Meteor using Leaflet JS. The problem is, I could only get map.panTo to work inside the Template.dynamicmap.rendered area. However, this makes it so anywhere you click on the map pans to the location.
This is the complete rendered area with id and access token removed.
Template.dynamicmap.rendered = function() {
var southWest = L.latLng(35.02035919622158, -121.21049926757814);
var northEast = L.latLng(42.4426214924114, -110.79740478515624);
var mybounds = L.latLngBounds(southWest, northEast);
var map = L.map('map_container',{zoomControl: false, maxBounds: [[37.00035919622158, -119.23049926757814],[40.4626214924114, -112.77740478515624]],}).setView([38.685509760012, -115.86181640625001], 10);
var w = window.innerWidth;
var h = window.innerHeight;
$('#map_container').css({width: w+'px', height: h+'px'});
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', {
bounds: mybounds,
maxZoom: 10,
minZoom: 9,
}).addTo(map);
L.Icon.Default.imagePath = 'packages/leaflet/images';
var marker = L.marker([38.685509760012, -115.86181640625001]).addTo(map);
map.fitBounds(bounds);
};
So I tried putting it in an Template event shown below, this button is not within the map area but still in the dynamicmap template. It does not work though.
Template.dynamicmap.events({
'click input.goto3':(function() {
map.panTo(L.latLng(38.685509760012, -115.86181640625001));
})
});
I receive the error:
"Uncaught ReferenceError: map is not defined"
in the console. Which I have been trying to wrap my head around but no luck. I was hoping someone here could point me in the right direction.
Here is my HTML Template.
<template name="dynamicmap">
<div class="containerbox">
<div class="map_container" id="map_container">
</div>
</div>
<input type="button" class="goto3" value="Go"/>
</template>
You need to make map a global variable:
var map = null;
Template.dynamicmap.rendered = function() {
var southWest = L.latLng(35.02035919622158, -121.21049926757814);
var northEast = L.latLng(42.4426214924114, -110.79740478515624);
var mybounds = L.latLngBounds(southWest, northEast);
map = L.map('map_container',{zoomControl: false, ...
...

Display number characters left to reach maxlength of a telerik:RadTextBox

My asp .net web application requires a telerik:RadTextBox that can accept 160 characters max. Every time a character is entered into this textbox, I want the number of remaining characters that i can type to be displayed near this textbox as a label.Can anyone tell me which event should i make use of and provide javascript code to implement this?
I have done something similar to this with a series of user controls that have text boxes in them. I would recommend using the onkey up and onkey down events to increase/lower your counter.
This is the javascript that we use.
<script type="text/javascript" language="Javascript">
//Character count script!
function textCounter(field, countfield, maxlimit) {
if (countfield == null) { return; }
if (field.value.length > maxlimit)
field.value = field.value.substring(0, maxlimit) + " Characters Remaining";
else
countfield.value = maxlimit - field.value.length + " Characters Remaining";
}
</script>
Here is something similar to the text box with the counter field below it.
<telerik:RadTextBox ID="txtTextBox" runat="server" />
<input readonly="readonly" enableviewstate ="false" type="text" runat="server" id="charCount" size="25" name="charCount" tabindex="-1" value=""
style="border: solid 0px white; display:none; background: white; font-size: 11px; color: #FF0000; text-align: right; float:right" />
The attributes are added onLoad if there is a maxlength for the textbox.
txtTextBox.Attributes.Item("onblur") = charCount.ClientID + ".style.display='none';"
txtTextBox.Attributes.Item("onfocus") = charCount.ClientID + ".style.display='block';"
txtTextBox.Attributes.Item("onkeyup") = "textCounter(this, " + charCount.ClientID + "," + myMaxLength.ToString + ");"
txtTextBox.Attributes.Item("onkeydown") = "textCounter(this, " + charCount.ClientID + "," + myMaxLength.ToString + ");"
When all this is combined it will shoe up the counter if you have set a max limit on it, only when that text box has focus. Once the focus is gone the script onblur hides the text box again. The counter is fired on the onkeyup and onkeydown so the count will stay accurate. It will count backwards to 0 and once it reaches 0 the user will not be able to enter more text.
here are some hints on your questions:
In order to count the number of characters and exclude line breaks, you can use the following:
<telerik:RadTextBox ID="RTB1" runat="server" TextMode="MultiLine" ClientEvents-OnKeyPress="KeyPress" />
<script type="text/javascript">
function KeyPress(sender, args)
{
var text;
if ($telerik.isIE || args.get_domEvent().rawEvent.keyCode == 0 || args.get_domEvent().rawEvent.keyCode == 13) // 13 : Enter key
{
text = escape(sender.get_value() + args.get_keyCharacter());
}
else
{
text = escape(sender.get_value());
}
while (text.indexOf("%0D%0A") != -1) // IE
{
text = text.replace("%0D%0A", " ");
}
while (text.indexOf("%0A") != -1)
{
text = text.replace("%0A", " ");
}
while (text.indexOf("%0D") != -1)
{
text = text.replace("%0D", " ");
}
var calculatedLength = unescape(text).length;
if (args.get_domEvent().rawEvent.keyCode == 8 && calculatedLength > 0) // 8 : backspace
{
calculatedLength -= 1;
}
document.title = calculatedLength;
}
</script>
This way you can do this.
Even you can check http://www.telerik.com/community/forums/aspnet-ajax/input/counting-characters.aspx for more details.
Thanks,
Use the onFocus client side event:
Eg.
textBox1.Attributes.Add("onFocus", "Counter('textBox1','LabelID',160)");
<script>
function Counter(textboxID, LabelID, MaxCharacters) {
var count = MaxCharacters - document.getElementById(textboxID).value.length;
document.getElementById(LabelID).innerHTML = count;
}
</script>

Resources