I have developed a Django web application showing interactive maps generated by Bokeh, and sent to the templates as script/div using 'components' (from bokeh.embed). All items (figure, slider, title) are shown correctly except DataTable, which I can show in a standalone document or in Jupyter, but not with 'components'.
I have read Bokeh DataTable not show in Flask, Embedding bokeh plot and datatable in flask and other threads, which helped me to fix the JS/CSS links, but it did not help with my problem.
I tried to wrap the DataTable inside different modules, like Panel, WidgetBox, etc., after reading https://github.com/bokeh/bokeh/issues/4507, without success. For simplicity, I used example data with no link to my data to generate the table in a separate Django view, and created a separate template.
I have run out of ideas for now. I know that widgets in Bokeh have had rendering issues, so I am guessing my issue could be related to those issues, but more likely to my lack of knowledge. The code is below.
DJANGO VIEW:
def datatable_test(request):
data = dict(
dates=[date(2014, 3, i + 1) for i in range(10)],
downloads=[randint(0, 100) for i in range(10)],
)
source = ColumnDataSource(data)
columns = [
TableColumn(field="dates", title="Date", formatter=DateFormatter()),
TableColumn(field="downloads", title="Downloads"),
]
data_table_mth = DataTable(source=source, columns=columns, width=400, height=280)
layout = column(
Spacer(width=100),
WidgetBox(data_table_mth),
)
script_table, div_table = components(layout)
output_file("DATATABLE TEST.html")
show(layout)
return render(request, 'integrated/datatable_test.html', {'script_table': script_table,'div_table': div_table})
DJANGO TEMPLATE:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>{% block title %}{% endblock %}</title>
<link href="https://cdn.bokeh.org/bokeh/release/bokeh-1.4.0.min.css" rel="stylesheet" type="text/css">
<link href="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-1.4.0.min.css" rel="stylesheet" type="text/css">
<link href="https://cdn.bokeh.org/bokeh/release/bokeh-tables-1.4.0.min.css" rel="stylesheet" type="text/css">
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-1.4.0.min.js"></script>
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-1.4.0.min.js"></script>
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-1.4.0.min.js"></script>
{{ script_table | safe }}
</head>
<body>
<section class="content">
<div class="row">
<div class="col-md-12">
<div class="box box-success">
<div class="box-body">
{{ div_table | safe }}
</div>
</div>
</div>
</div>
</section>
</body>
Output as embedded table is blank:
output as embedded table
Output as standalone html works:
output as standalone
As bigreddot suggested, I opened the browser console, showing the following error messages when the DataTable is embedded in its original view/template:
browser console
Related
I have been trying to get an embedded Power BI report hosted on a flask page. When the page attempts to load, the console throws CORS errors left and right1 and it seems as though the packets carrying the data are getting blocked.2 I have tried setting 'Access-Control-Allow-Origin' to
a wildcard in our response header, but it doesn't seem to solve the issue. However we believe it is at least related to headers because when we try to run it on a version of chrome with security disabled, the report will load as it should. Another unit that works parallel to me has been able to get the same(ish) code working on a C# hosted site and they didn't need to add any origin headers or anything so I'm fairly certain this is an issue specific to flask/power bi. Here is the relevant code from our route serving file:
#app.route('/pm/getembedinfo', methods=['GET'])
def get_embed_info():
'''Returns report embed configuration'''
config_result = utils.Utils.check_config(app)
if config_result is not None:
return json.dumps({'errorMsg': config_result}), 500
try:
embed_info = pbiembedservice.PbiEmbedService().get_embed_params_for_single_report(app.config['WORKSPACE_ID'], app.config['REPORT_ID'])
# embed_info.headers.add('Access-Control-Allow-Origin', '*')
response = make_response(embed_info)
response.headers['Access-Control-Allow-Origin'] = '*'
return response
except Exception as ex:
return json.dumps({'errorMsg': str(ex)}), 500
#app.route('/pm/favicon.ico', methods=['GET'])
def getfavicon():
'''Returns path of the favicon to be rendered'''
return send_from_directory(os.path.join(app.root_path, 'static'), 'img/favicon.ico', mimetype='image/vnd.microsoft.icon')
#app.route('/pm/power_bi_dashboard', methods=["GET"])
def power_bi_dashboard():
response = make_response(render_template('power_bi_dashboard.html'))
response.headers.add('Access-Control-Allow-Origin', '*')
return response
And here is the relevant part of the html template:
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<link rel="stylesheet" href="{{ url_for('static', filename='css/index.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/global.css') }}">
<title>Traffic Monitoring Dashboard</title>
</head>
<body>
<header class="embed-container col-lg-12 col-md-12 col-sm-12 shadow">
<p>
Traffic Monitoring Dashboard
</p>
</header>
<main class="row">
<section id="report-container" class="embed-container col-lg-offset-4 col-lg-7 col-md-offset-5 col-md-7 col-sm-offset-5 col-sm-7 mt-5">
</section>
<!-- Used to display report embed error messages -->
<section class="error-container m-5">
</section>
</main>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#4.5.3/dist/js/bootstrap.min.js" integrity="sha384-w1Q4orYjBQndcko6MimVbzY0tgp4pWB4lZ7lr30WKz0vr/aWKhXdBNmNb5D92v7s" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/powerbi-client/2.15.1/powerbi.min.js" integrity="sha512-OWIl8Xrlo8yQjWN5LcMz5SIgNnzcJqeelChqPMIeQGnEFJ4m1fWWn668AEXBrKlsuVbvDebTUJGLRCtRCCiFkg==" crossorigin="anonymous"></script>
<script src="{{ url_for('static', filename='js/index.js') }}"></script>
</body>
I'm trying to add a maintenance page to my Flask site. I have created a route called /maintenance that renders my maintenance.html template. I then added an #app.before_request to check whether the site is in maintenance mode (a Boolean value).
When I request the /maintenance route directly from the browser, the page displays fine:
However, when the route is called from the #app.before_request, it displays like this:
As can be seen from the console window, I'm getting the following message:
'Resource interpreted as Stylesheet but transferred with MIME type text/html'
Here is the code for the /maintenance route and #app.before_request:
#app.before_request
def check_for_maintenance():
if maintenance == True and request.path != url_for('maintenance'):
return redirect(url_for('maintenance'))
#app.route('/maintenance')
def maintenance():
if request.method =='GET':
return render_template('maintenance.html')
Here's the code for the maintenance page (ish, it inherits lots of parent Jinja templates but the important stuff is here):
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="/static/css/theme.css">
<link href="{{ url_for('static', filename='fonts/peenu/stylesheet.css') }}" rel="stylesheet">
<link href="{{ url_for('static', filename='favicon.ico') }}" rel="icon">
</head>
<body>
<div id="maintenanceBackground">
<div id="maintenanceTextParent">
<img id="spannerIcon" src="/static/media/graphics/spanner.png" alt="Spanner icon">
<h1 id="maintenanceText1">We're doing some work at the moment</h1>
<h2 id="maintenanceText2">We hope to be running again soon. Please try again later.</h2>
<img id="whiteLogo" src="/static/media/graphics/logoWhite.png" alt="Custom Crochet logo">
</div>
</div>
</body>
</html>
This is somewhat related to flask. If you try to access the html directly without flask's webserver, the html page loads with applied css, as expected.
To be more specific, actual solution is
to create a "css" folder in "static" folder.
add css in path of ".css" file (update all occurrence for any .css file with expected relative path)
eg.
change => href="{{ url_for('static', filename='stylesheet.css') }}" to href="{{ url_for('static', filename='css/stylesheet.css') }}" OR
change => href="../static/main.css" to href="../static/css/main.css"
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
In your case
try moving stylesheet.css from "fonts/peenu/stylesheet.css" to "static/css" folder.
change => href="{{ url_for('static', filename='fonts/peenu/stylesheet.css') }}"
to
href="{{ url_for('static', filename='css/stylesheet.css') }}"
I had spent some time on this issue and was able to resolve it with above mentioned solution.
I am developing a Flask web application to show data in a DataTable and also build interactive reports by Bokeh. My below code to show bokeh DataTable not work.
from flask import Flask, render_template, request
import pandas as pd
from bokeh.embed import components
from bokeh.models.widgets import DataTable, DateFormatter, TableColumn
from bokeh.models.sources import ColumnDataSource
app = Flask(__name__)
# Load the Iris Data Set
iris_df = pd.read_csv("/data/iris.data", names=["Sepal Length", "Sepal Width", "Petal Length", "Petal Width", "Species"])
#app.route('/ShowIrisDataTable/')
def index():
cols = [
TableColumn(field='Sepal Length', title='Sepal Length'),
TableColumn(field='Sepal Width', title='Sepal Width'),
TableColumn(field='Petal Length', title='Petal Length'),
TableColumn(field='Petal Width', title='Petal Width'),
TableColumn(field='Species', title='Species')
]
data_table = DataTable(columns=cols, source=ColumnDataSource(iris_df), fit_columns=True)
script, div = components(data_table)
return render_template("iris_index5.html", script=script, div=div)
if __name__ == '__main__':
app.run(port=5000, debug=True)
my html file is as below:
<html>
<head>
<link
href="http://cdn.bokeh.org/bokeh/release/bokeh-0.12.16.min.css"
rel="stylesheet" type="text/css">
<link
href="http://cdn.bokeh.org/bokeh/release/bokeh-widgets-0.12.16.min.css"
rel="stylesheet" type="text/css">
<script src="http://cdn.bokeh.org/bokeh/release/bokeh-0.12.16.min.js"></script>
<script src="http://cdn.bokeh.org/bokeh/release/bokeh-widgets-0.12.16.min.js"></script>
</head>
<body>
<H1>Iris Data Table version 5</H1>
{{ script|safe }}
{{ div|safe }}
</body>
</html>
My web application only shows heading "Iris Data Table version 5" but not the Bokeh DataTable also no error message.
I cannot figure where is wrong, appreciate your help.
You are not including the JS/CSS files for tables. They are relatively large, so they are split into their own files so people that don't make use of tables don't have to pay the cost of loading the resources. Below is a working template. Note I have also updated the CDN urls to point at cdn.bokeh.org. The old locations will work indefinitely, but anyone who can should use the new locations.
<html>
<head>
<link
href="http://cdn.bokeh.org/bokeh/release/bokeh-0.12.16.min.css"
rel="stylesheet" type="text/css">
<link
href="http://cdn.bokeh.org/bokeh/release/bokeh-widgets-0.12.16.min.css"
rel="stylesheet" type="text/css">
<link
href="http://cdn.bokeh.org/bokeh/release/bokeh-tables-0.12.16.min.css"
rel="stylesheet" type="text/css">
<script src="http://cdn.bokeh.org/bokeh/release/bokeh-0.12.16.min.js"></script>
<script src="http://cdn.bokeh.org/bokeh/release/bokeh-widgets-0.12.16.min.js"></script>
<script src="http://cdn.bokeh.org/bokeh/release/bokeh-tables-0.12.16.min.js"></script>
</head>
<body>
<H1>Iris Data Table version 5</H1>
{{ script|safe }}
{{ div|safe }}
</body>
</html>
I tried to integrate this(having a layout.html and index.html) into my app. Before starting I only had index.html with all of my css/javascript includes at the top.
Current file struct
/app
- app_runner.py
/templates
- layout.html
- index.html
/static
/styles
- mystyle.css
Layout.html (mostly css and javascript CDN and my stylesheet)
<!doctype html>
<!-- Latest bootstrap compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<!-- Optional bootstrap theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
<!-- jquery -->
<script
src="https://code.jquery.com/jquery-3.1.1.min.js"
integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
crossorigin="anonymous"></script>
<!-- Latest bootstrap compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<!-- jstree -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/themes/default/style.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/jstree.min.js"></script>
<!-- my stylesheet -->
<link rel='stylesheet' type='text/css' href="{{url_for('static',filename='styles/mystyle.css')}}" />
<script type="text/javascript">
var $SCRIPT_ROOT = {{ request.script_root|tojson|safe }};
</script>
{% block body %}{% endblock %}
The page, for the most part, renders the same: The jstree appears, bootstrap works, and the rest of my styling is applied. In my css file I have a line that doesn't get applied:
td {
padding: 5px;
}
The developer console shows padding:0, which comes from a bootstrap script. If I change it in the developer console I can get it to change to 5px.
I've heard using !important is bad practice but I tried it anyway with no change. I tried adding a class to all my td so it'd have higher precedent (based on this answer) and have that style (.my_row{padding:5px;}) apply but again it doesn't change. So it seems my css isn't being applied to my table. Other parts of mystyle.css work though.
Any thoughts on why the padding isn't being applied to my table?
So it turns out my stylesheet wasn't refreshing in the cache. I found an answer on this site.
I added these lines of code to my python (app-runner.py)
#app.context_processor
def override_url_for():
return dict(url_for=dated_url_for)
def dated_url_for(endpoint, **values):
if endpoint == 'static':
filename = values.get('filename', None)
if filename:
file_path = os.path.join(app.root_path,
endpoint, filename)
values['q'] = int(os.stat(file_path).st_mtime)
return url_for(endpoint, **values)
I have been trying to style bokeh widgets with a css file in flask that I modified from the gapminder demo. In particular, I am currently trying to style the dropdown, tab and slider widgets without much progress. I was able to style the tooltips using the gapminder css example, but would ultimately like to know if there are other examples or, even better, a listing of all of the bokeh style options (i.e. .bk-... styles). I'm not sure if this should work properly, as I'm still learning web dev, by my current index.html file in flask looks like:
<html>
<head>
<link
href="https://cdn.bokeh.org/bokeh/release/bokeh-0.12.1.min.css"
rel="stylesheet" type="text/css">
<link
href="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-0.12.1.min.css"
rel="stylesheet" type="text/css">
<link
rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles/gapminder.css') }}">
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-0.12.1.min.js"></script>
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-0.12.1.min.js"></script>
{{ script | safe }}
</head>
<body>
<div class=page>
{{ div | safe }}
</div>
</body>
</html>
Thanks in advance for the help.
Not sure if you are still searching for a response, but here is what I have done to adress this issue.
<style>
{% include 'styles.css' %}
.bk-root .bk-toolbar-right .bk-button-bar-list .bk-toolbar-button:hover .bk-tip {
color: #5DADE2;
}
.bk-root .bk-slider-parent input[type="text"]{
color: #FDFEFE;
}
</style>
It is quite manual, in that I first generated the bokeh plots, inspected the widget elements i wanted to change then simply added this into the index.html file. If you want to see which attributes you can edit, just inspect them and you will see them there.
For this example i changed the color of the tool names when you hover on them and also the slider value color.
I also had a seperate .css file which i included, so you could move it all in there.