Embedding a bokeh plot in Flask - javascript

I am expecting to get a simple line bokeh plot returned by Flask, but what I get when I browse to localhost:5002/simpleline is this:
('', '
')
I have two files. The Python file:
from bokeh.plotting import figure, show, output_file
from bokeh.embed import components
from flask import Flask, render_template
app=Flask(__name__)
#app.route('/simpleline/')
def simpleLine():
fig=figure(title="Sensor data")
fig.line([1,2,3,4],[2,4,6,8])
div=components(fig)
return render_template('simpleline.html',div=div)
show(fig)
if __name__ == "__main__":
app.run(debug=True,port=5002)
And the HTML template:
<!doctype html>
<html>
<head>
<title>Figure examples</title>
<link rel="stylesheet" href="http://cdn.bokeh.org/bokeh-0.7.1.min.css" type="text/css" />
<script type="text/javascript"src="http://cdn.bokeh.org/bokeh-0.7.1.min.js"></script>
</head>
<body>
<div class='bokeh'>
{{ div|safe }}
</div>
</body>
</html>
I am sure I am missing something essential here.
After mn's answer, it was found out that components() produces two elements, a Javascript string, and an html div. So, I updated my scripts as follows, but this time the web page shows as blank.
from bokeh.plotting import figure, show, output_file
from bokeh.embed import components
from flask import Flask, render_template
app=Flask(__name__)
#app.route('/simpleline/')
def simpleLine():
fig=figure(title="Sensor data")
fig.line([1,2,3,4],[2,4,6,8])
global script
global div
script,div=components(fig)
return render_template('simpleline.html',div=div,script=script)
output_file("simpleline.html")
show(fig)
fig=figure(title="Sensor data")
fig.line([1,2,3,4],[2,4,6,8])
script,div=components(fig)
if __name__ == "__main__":
app.run(debug=True,port=5002)
And the HTML template:
<!doctype html>
<html>
<head>
<title>Figure examples</title>
<link rel="stylesheet" href="http://cdn.bokeh.org/bokeh-0.9.0.min.css" type="text/css" />
<script type="text/javascript" src="http://cdn.bokeh.org/bokeh-0.9.0.min.js"></script>
{{ script|safe }}
</head>
<body>
<div class='bokeh'>
{{ div|safe }}
</div>
</body>
</html>
I tried all bokeh-0.7.1.min.js, 0.9, and 0.10, but I still got the same blank page.

components() returns (script, div) tuple with <script> that contains the data for your plot and an accompanying <div> tag that the plot view is loaded into:
http://docs.bokeh.org/en/latest/docs/user_guide/embed.html#components
script, div = components(fig)
return render_template('simpleline.html',div=div, script=script)
template
<!doctype html>
<html>
<head>
<title>Figure examples</title>
<link rel="stylesheet" href="http://cdn.bokeh.org/bokeh/release/bokeh-0.10.0.min.css" type="text/css" />
<script type="text/javascript" src="http://cdn.bokeh.org/bokeh/release/bokeh-0.10.0.min.js"></script>
{{ script|safe }}
</head>
<body>
<div class='bokeh'>
{{ div|safe }}
</div>
</body>
</html>

Alternatively, you can also use autoload_static instead of components if you want the bokeh js and css to load automatically. Also you can save the js into a filepath and use only the div in the html to access it.
Here is a sample code that I worked with:
from bokeh.embed import autoload_static
from bokeh.resources import CDN
.............
.............
js, div = autoload_static(bar, CDN, '/static/bokeh/plot.js')
with open('static/bokeh/plot.js', 'w') as f:
f.write(js)
And then in the html file include only the div tag (includes the path of the js script).
<!doctype html>
<html>
<head>
<title>Figure examples</title>
</head>
<body>
<div class='bokeh'>
{{ div|safe }}
</div>
</body>
</html>

Related

Flask loading icon on page load

from flask import Flask, render_template, Response, request, redirect, url_for
app = Flask(__name__)
app.config['TEMPLATES_AUTO_RELOAD'] = True
#app.route("/", methods=["POST", "GET"])
def index():
if request.method == "POST":
return render_template("index.html")
if __name__ == '__main__':
app.run(debug=True)
<html>
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<style>
div#loading {
width: 50px;
height: 50px;
display: none;
background: url('https://i.giphy.com/3oEjI6SIIHBdRxXI40.gif') center no-repeat;
cursor: wait;
padding-left:100%;
}
</style>
</head>
<body>
<form method="POST">
<input type="text">
<button type="submit" onclick="loading();">
<div id="loading"></div>
<div id="content">
<i class="fas fa-search"></i>
</div>
</button>
</form>
<script type="text/javascript">
function loading(){
$("#loading").show();
$("#content").hide();
}
</script>
</body>
</html>
I'm building a Flask app, where when you press a button, a loader should replace the search glass icon with a loading gif.
At the moment, the gif isn't appearing upon clicking the button.
When I remove display:none from the loading style, the gif appears, so I know it's there.
You are using JQuery to show and hide the elements, but you have not included it in the template.
So include a script tag like
<script
src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
crossorigin="anonymous"></script>
before the script tag where you're referencing JQuery
I figured I already had a div id = content and so it was removing the entire div. Remember to check your IDs!

Why can I not change a html element with JS?

I'm trying to get a JS script to insert HMTL on a python flask server and it doesn't seem to want to run.
File Structure:
project
static
css
style.css
templates
demo.html
download.html
index.html
wrongLink.html
main.py
Here is the flask code that runs the webserver:
from flask import Flask, render_template, send_file
from flask import request, redirect
app = Flask(__name__)
#app.route('/')
def main():
return render_template('demo.html')
I also render some templates like this:
return render_template('download.html',
thumb=thumb, title=title, options=options, counter=counter)
I realised that I'm having trouble specifically with one piece of JS in the download.html file:
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<link href="{{ url_for('static', filename='css/style.css') }}"
rel="stylesheet" type="text/css">
</head>
<body>
<div>
<form action="/getVideo" method="post">
<input type="text" name="Link" value="{{ Link }}">
<input type="submit" value="Convert">
</form>
<img src="{{ thumb }}" alt="Thumbnail" width="480" height="270">
<p>{{ title }}</P>
<p id="demo"></p>
<form id="options">
<input type="submit" value="Download">
</form>
</div>
<script type="text/javascript">
window.alert("JS works");
var i;
var options = JSON.parse{{options | tojson}};
for (i = 0; i < options.length; i++) {
out += '<input type="radio" value="' + options[i]["res"] += '"><br>';
}
document.getElementById("demo").innerHTML = "hi";
</script>
</body>
</html>
Neither the alert window or the element edit execute so I'm not sure what's happening there.

Why emitted events of livewire is not triggered?

In laravel 7 learning livewire/livewire 1.3 I encountered that emitted
events are not always triggered
I created component with command
php artisan make:livewire hostel/hostelsHomepageSpotlight
and simplifying the code I do not see alert of event.
In app/Http/Livewire/Hostel/HostelsHomepageSpotlight.php :
<?php
namespace App\Http\Livewire\Hostel;
use Auth;
use DB;
use App\Config;
use App\Hostel;
use App\HostelImage;
use App\library\CheckValueType;
use App\Settings;
use Livewire\Component;
class HostelsHomepageSpotlight extends Component
{
public function render()
{
$hostels = [];
$current_page= 1;
$hostel_rows_count = Hostel
::getByStatus('A')
->count();
$this->emit('hostelsHomepageSpotlightOpened', [ 'mode'=> 'hostels_homepage_spotlight', 'current_page'=>$current_page, 'hostel_rows_count'=>$hostel_rows_count ] ); // EMIT EVENT
return view('livewire.hostel.hostels-homepage-spotlight', [
'hostelsDataRows' => $hostels,
'hostel_rows_count'=> $hostel_rows_count,
'current_page'=> $current_page,
]);
}
}
and in resources/views/livewire/hostel/hostels-homepage-spotlight.blade.php:
<div>
<h1>hostelsHomepageSpotlightOpened</h1>
</div>
<script>
// If to uncomment line below I see alert
// alert( 'resources/views/livewire/hostel/hostels-homepage-spotlight.blade.php::' )
window.livewire.on('hostelsHomepageSpotlightOpened', data => {
// I DO NOT SEE ALERT BELOW ANYWAY
alert( 'hostelsHomepageSpotlightOpened::' )
console.log('facility_opened data::')
console.log(data)
// alertsInit(data.mode)
// lazyImagesInit("img.lazy_image")
})
</script>
Why event is not triggered ? Is there is a way to debug it ?
UPDATED # 2:
I know the rule about wrapping div(without any class or styles definitions).
Have I also to remove JS code ?
I tried to move all JS code in resources/js/app.js :
window.$ = window.jQuery = require('jquery');
require('./bootstrap');
var Turbolinks = require("turbolinks")
Turbolinks.start()
// If to uncomment the line below I see it
// alert( '::resources/js/app.js' )
window.livewire.on('hostelsHomepageSpotlightOpened', data => {
// I do not see this alert
alert( 'hostelsHomepageSpotlightOpened::' )
console.log('facility_opened data::')
console.log(data)
// alertsInit(data.mode)
// lazyImagesInit("img.lazy_image")
})
and in my resources/views/layouts/app.blade.php :
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}" xmlns:livewire="http://www.w3.org/1999/html">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Laravel:Livewire</title>
<!-- Fonts -->
<link href="https://fonts.googleapis.com/css?family=Nunito:200,600" rel="stylesheet">
<link href="{{ asset('css/bootstrap.min.css') }}" rel="stylesheet" type="text/css">
<link rel="icon" type="image/png" href="/favicon.ico"/>
<link href="/css/app.css" rel="stylesheet">
<script src="{{ asset('js/lazyload.js') }}"></script>
<!-- Styles -->
#livewireStyles
#livewireScripts
<script src="{{ asset('/js/app.js') }}"></script>
<script src="{{ asset('/js/app/app_funcs.js') }}"></script>
</head>
<body class="text-center">
<div class="flexbox-parent page_container " id="page_content">
<header class="flexbox-item header">
<nav class="navbar navbar-expand-lg navbar-light bg-light">
...
</nav>
</header>
<main class="flexbox-item fill-area content flexbox-item-grow">
#yield('content')
</main>
<footer class="flexbox-item footer ml-3 mr-3">
...
<p class="m-2">copyright_text</p>
</footer>
</div>
</body>
</html>
And my code is nit triggered anywat!
I suppose that is valid structure of my app as app.js AFTER #livewireStyles
and #livewireScripts
UPDATED # 3:
I tried and that does not work. I have login form :
<article class="page_content_container">
...
<form class="form-login" wire:submit.prevent="submit">
<input
wire:model.lazy="form.email"
name="email"
id="email"
class="form-control editable_field"
placeholder="Your email address"
autocomplete=off
>
</form>
...
</article> <!-- page_content_container -->
{{--#push('scripts')--}}
<script>
$("#email").focus();
</script>
{{--#endpush--}}
When #push/#endpush are commented as on lines above it works ok and focus is set to email input.
But if to uncomment these 2 lines focus is not set.
I modified my resources/views/layouts/app.blade.php :
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Laravel:Livewire</title>
<!-- Fonts -->
<link href="https://fonts.googleapis.com/css?family=Nunito:200,600" rel="stylesheet">
<link href="{{ asset('css/bootstrap.min.css') }}" rel="stylesheet" type="text/css">
<link rel="icon" type="image/png" href="/favicon.ico"/>
<link href="/css/app.css" rel="stylesheet">
<!-- Styles -->
#livewireStyles
<script src="{{ asset('/js/app.js') }}"></script>
<script src="{{ asset('js/lazyload.js') }}"></script>
<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine#v2.x.x/dist/alpine.min.js" defer></script>
#livewireScripts
#stack('scripts')
<script src="{{ asset('/js/app/app_funcs.js') }}"></script>
app.js - is first as bootstrap and jquery are included there...
Thanks!
Livewire expects components wrapped by a div element.
Sample:
< div>
Your content...
</ div>
What I am saying is that I am not sure you can include javascript in your Livewire blade. Try by moving it out to your app.js file and see if it works because the rest looks good.
I remember having trouble just because the blade’s first line was a html comment, instead of 🙈
So, always, first line of your livewire blade must be < div>, and last line </ div>
Hope that helps!
If you want to write script under livewire blade try this way. in your master layout put under #livewireScripts
#stack('scripts')
Now you can push scripts in this stack from your livewire blade file like this:
#push('scripts')
<script>
// some js code
</script>
#endpush
UPDATED: It makes sense why in your case it does NOT work. You should NOT emit the event in the RENDER function IFF you want to listen for it in the same view that is about to be rendered. In simple words for your case, the emit happens before the view loads, thus, by the moment your view is ready, it will be a 'bit' late to listen to it, you lost it! :-)
Solution: put the JS (the window.livewire.on... ) one step outside so it will be already ready by the moment you emit the event in the render.
In simple words, place the JS code in the scripts section of the parent file, the file you include the following
#livewire('hostel.hostels-homepage-spotlight')
P.S. When you are dealing with livewire, to listen for an event or fire one,
do not forget to wrap it in the document ready, i.e.,
$( document ).ready(function() {
livewire.emit('event_foo', 'foooo');
});
Thus, your spotlight PARENT page should look something like this:
<script>
$( document ).ready(function() {
window.livewire.on('hostelsHomepageSpotlightOpened', data => {
alert( 'hostelsHomepageSpotlightOpened::' )
console.log('facility_opened data::')
console.log(data)
});
});
</script>
Cheers,

Is it the optimized way of mixing laravel blade and vuejs

I am currently make the app.blade.php as
<!DOCTYPE html>
<html>
<head>
<title> abc</title>
<link rel="stylesheet" href='{{URL::asset('/css/style.css ')}}' />
<link rel="stylesheet" href='{{URL::asset('/css/app.css ')}}' />
<script>
window.Laravel = <?php echo json_encode([
'csrfToken' => csrf_token(),
]); ?>
</script>
</head>
<body>
<div class="wrapper" id="app" v-cloak>
#yield('content')
</div>
<script src="{{ URL::asset('js/app.js') }}"></script>
<script>
var vm = new Vue({
el: '#app',
#yield('vue')
});
</script>
</body>
</html>
And subsequent pages like dashboard.blade.php as
#extends('layouts.app')
#section('title', 'customer :')
#section('content')
<titlebar></titlebar>
<dashboard-page
:data=data
:options=options
#update=updatethedata
><dashboard-page>
#endsection
#section('vue')
data:{
data:{...},
options={...},
},
methods:{
updatethdata:function(){
...;
}
},
#endsection
It works as intended. but i don't know this is how it should be merged or there as some better ways to do it .
It gives me access to both blade and vue to customize my application . but it makes the code much difficult as the js is in blade file which doesnot get minified. more over none syntax highlighter works , as it is not in a script tag.

.gexf -format node graph visualization

To visualize a node graph Sigma.js looks fantastic. I tried some examples but can't get my graph to display. I used example code and tried to plug in my .gexf file, but nothing displays. This is what I took from the Sigma.js example :
function init() {
// Instanciate sigma.js and customize rendering :
var sigInst = sigma.init(document.getElementById('sigma-example')).drawingProperties({
defaultLabelColor: '#fff',
defaultLabelSize: 14,
defaultLabelBGColor: '#fff',
defaultLabelHoverColor: '#000',
labelThreshold: 6,
defaultEdgeType: 'curve'
}).graphProperties({
minNodeSize: 0.5,
maxNodeSize: 5,
minEdgeSize: 1,
maxEdgeSize: 1
}).mouseProperties({
maxRatio: 32
});
// Parse a GEXF encoded file to fill the graph
// (requires "sigma.parseGexf.js" to be included)
sigInst.parseGexf('donornet.gexf');
// Draw the graph :
sigInst.draw();
}
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", init, false);
} else {
window.onload = init;
}
I replaced the .gexf file with my own donornet.gexf file and saved it as donornet.js. I then used code from this example (from Max De Marzi), which I replaced with my donornet.js file:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>Donornet and Sigma.js Example</title>
<script type="text/javascript" src="sigma.min.js"></script>
<script type="text/javascript" src="sigma.parseGexf.js"></script>
<script type="text/javascript" src="sigma.forceatlas2.js"></script>
<link type="text/css" rel="stylesheet" href="neo_sigma.css"/>
</head>
<body>
<h1>Donornet and Sigma.js Example</h1>
<div class="buttons-container">
<button class="btn" id="stop-layout">Stop Layout</button>
<button class="btn" id="rescale-graph">Rescale Graph</button>
</div>
<div class="span12 sigma-parent" id="sigma-example-parent">
<div class="sigma-expand" id="sigma-example"></div>
</div>
<script type="text/javascript" src="donornet.js"></script>
</body>
</html>
All files are in the same folder. parseGexf.js is in the same folder as donornet.js and donornet.gexf.
You don't have to save .gexf file as a .js file. Just leave it as a gexf file and upload it into the script's folder. Remove the line with <script src="donornet.js">. Try to run again. If it doesn't work, also remove the buttons div. Check out the source on http://noduslabs.com/socialplayer/smmrussia/

Categories

Resources