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>
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 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
Working with Dash 0.22.0 and Python 2.7.12. Plotly is 3.1.0 but not used in the following example.
I am trying to create a minimal app that should work completely offline.
Instead of loading from remote dash_html_components/bundle.js, dash_renderer/bundle.js, react.min.js and react-dom.min.js, I put their local copies in /assets/js. I want to tell Dash to use only the local copies of these files.
I read Assets files & index customizations #286 and if I understood well the following example should work:
# -*- coding: utf-8 -*-
import dash
import dash_core_components as dcc
import dash_html_components as html
app = dash.Dash()
# default values
app.config.assets_folder = 'assets' # The path to the assets folder.
app.config.include_asset_files = True # Include the files in the asset folder
app.config.assets_external_path = "" # The external prefix if serve_locally == False
app.config.assets_url_path = '/assets' # the local url prefix ie `/assets/*.js`
app.layout = html.Div(
[html.H1("this is a test")]
)
if __name__ == '__main__':
app.run_server(debug=True)
HTML source:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>Dash</title>
<link rel="stylesheet" href="/assets/css/materialize.css">
<link rel="stylesheet" href="/assets/css/materialize.min.css">
<link rel="stylesheet" href="/assets/material-icons/material-icons.css">
</head>
<body>
<div id="react-entry-point">
<div class="_dash-loading">
Loading...
</div>
</div>
<footer>
<script id="_dash-config" type="application/json"<{"requests_pathname_prefix": "/", "url_base_pathname": "/"}</script>
<script src="https://unpkg.com/react#15.4.2/dist/react.min.js"></script>
<script src="https://unpkg.com/react-dom#15.4.2/dist/react-dom.min.js"></script>
<script src="https://unpkg.com/dash-html-components#0.11.0/dash_html_components/bundle.js"></script>
<script src="/assets/js/dash_html_components_0.11.0/bundle.js"></script>
<script src="/assets/js/react_15.4.2/react-dom.min.js"></script>
<script src="/assets/js/react_15.4.2/react.min.js"></script>
<script src="/assets/js/dash_renderer_0.13.0/bundle.js"></script>
<script src="/assets/js/materialize_1.0.0.rc2/materialize.js"></script>
<script src="/assets/js/materialize_1.0.0.rc2/materialize.min.js"></script>
<script src="/assets/material-icons/iconjar-map.js"></script>
<script src="https://unpkg.com/dash-renderer#0.13.0/dash_renderer/bundle.js"></script>
</footer>
</body>
</html>
As you can see, my local js files are loaded from /assets, but it keeps loading the same files from https://unpkg.com/...
Is there a way to avoid this?
It looks like I missed a simpler solution. I put it here if somebody is trying to to the same.
Don't include a local copy of dash libraries (dash_html_components/bundle.js, dash_renderer/bundle.js, react.min.js and react-dom.min.js) in /assets.
Use /assets only for js and css files not related to Dash and React. In my case materialize.js, iconjar-map.js and their respective CSS.
Adding instead:
app.css.config.serve_locally = True
app.scripts.config.serve_locally = True
will do the trick.
Code is now:
# -*- coding: utf-8 -*-
import dash
import dash_core_components as dcc
import dash_html_components as html
app = dash.Dash()
# default values
app.css.config.serve_locally = True
app.scripts.config.serve_locally = True
app.config.assets_folder = 'assets' # The path to the assets folder.
app.config.include_asset_files = True # Include the files in the asset folder
app.config.assets_external_path = "" # The external prefix if serve_locally == False
app.config.assets_url_path = '/assets' # the local url prefix ie `/assets/*.js`
app.layout = html.Div(
[ html.H1("This is a test")]
)
if __name__ == '__main__':
app.run_server(debug=True)
and the resulting html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>Dash</title>
<link rel="stylesheet" href="/assets/css/materialize.min.css">
<link rel="stylesheet" href="/assets/material-icons/material-icons.css">
</head>
<body>
<div id="react-entry-point">
<div class="_dash-loading">
Loading...
</div>
</div>
<footer>
<script id="_dash-config" type="application/json">{"requests_pathname_prefix": "/", "url_base_pathname": "/"}</script>
<script src="/_dash-component-suites/dash_renderer/react#15.4.2.min.js?v=0.13.0"></script>
<script src="/_dash-component-suites/dash_renderer/react-dom#15.4.2.min.js?v=0.13.0"></script>
<script src="/_dash-component-suites/dash_html_components/bundle.js?v=0.11.0"></script>
<script src="/assets/js/materialize_1.0.0.rc2/materialize.min.js"></script>
<script src="/assets/material-icons/iconjar-map.js"></script>
<script src="/_dash-component-suites/dash_renderer/bundle.js?v=0.13.0"></script>
</footer>
</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 setup a Flask app on a VPS and everything seems to work fine;
When i restart apache everything works fine and i got this:
html table
if I reload the browser page the data disappear and only remains the table header; if I want to see again the data I have to restart the apache server, and this is the big problem that I can't figure out.
my data stricture is the following:
|----FlaskApp
|---------FlaskApp
| +----main.html
|--------------static
|--------------templates
| +----elenco.py
| +----__init__.py
What I try to do is to connect to a SQL Server DB with _mssql, query the database and display the results in a html table.
This is the content of the files:
init.py
from flask import Flask, render_template
import _mssql
from elenco import Elenco_chiamate
Chiamate = Elenco_chiamate()
app = Flask(__name__)
#app.route('/')
def homepage():
return render_template("main.html", chiamate_html = Chiamate)
if __name__ == "__main__":
app.run()
elenco.py
import _mssql
def Elenco_chiamate():
conn = _mssql.connect(server='xxxxxxx', user='xxxxx', password='xxxxx')
conn.execute_row('SELECT TOP 100 * FROM ASSET_VIEW')
return conn
conn.close()
main.html
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="utf-8">
<title>Python Programming Tutorials</title>
<script
src="https://code.jquery.com/jquery-3.1.1.min.js"
integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
crossorigin="anonymous"></script>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Latest 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 theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
</head>
<body>
<table class="table table-striped table-bordered table-hover table-condensed">
<tr>
<th>
INVENTARIO
</th>
<th>
SERIALE
</th>
<th>
APPARECCHIATURA
</th>
</tr>
{% for row in chiamate_html %}
<tr>
<td>{{row['NUM']}}</td>
<td>{{row['N_SERI']}}</td>
<td>{{row['NOM']}}</td>
</tr>
{% endfor %}
</table>
</body>
</html>
You are calling Elenco_chiamate() at module level, so it will only be called once - when the module is first imported.
Call it inside the view function instead.