Как встроить виджет DataTable в веб-приложение Python Flask - PullRequest
1 голос
/ 22 марта 2019

Извинения, если на этот вопрос ответили где-то еще в StackOverflow, я приложил все усилия, чтобы найти ответ, прежде чем публиковать этот вопрос.

Я работаю над созданием веб-приложения на основе Flask, используя Bokeh для визуализации данных на работе. У меня не было проблем с встраиванием точечных / линейных графиков с использованием bokeh.embed.components и bokeh.plotting.figure.

Я хотел бы отобразить данные, которые используются для создания графика, в виджете DataTable под графиком. К сожалению, использование компонентов для генерации скрипта и div не работает для виджетов. Компоненты также не работают при использовании столбца, строки или макета, созданного с помощью bokeh.layouts.

Общий макет моего кода - это файл Python, который содержит мое приложение Flask, и файл HTML, который содержит макет моей веб-страницы. Общая схема файла Python приведена ниже:

from flask import Flask, render_template
import pandas as pd
import numpy as np
from bokeh.models import ColumnDataSource
from bokeh.models.widgets import DataTable, TableColumn
from bokeh.plotting import figure
from bokeh.layouts import widgetbox, column
from bokeh.embed import components

app = Flask(__name__)
x = np.linspace(0, 2, 1000)
y = np.sin(x)
df = pd.DataFrame({"x": x, "y":y}) # Not sure how to provide sample data

@app.route("/")
def index():
    p = figure()
    p.scatter(df['x'], df['y'])

    data_source = ColumnDataSource(df)
    columns = [
        TableColumn(field="field1", title="Field 1"),
        TableColumn(field="field2", title="Field 2"),
        TableColumn(field="field3", title="Field 3"),
    ]

    data_table = DataTable(source=data_source, columns=columns)
    script, div = components(column(p, widgetbox(data_table)))
    return render_template('sample.html', script=script, div=div)

Шаблон HTML ("sample.html") будет выглядеть примерно так:

<html>
<head>
<link
    href="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.css"
    rel="stylesheet" type="text/css">
<link
    href="http://cdn.pydata.org/bokeh/release/bokeh-widgets-1.0.4.min.css"
    rel="stylesheet" type="text/css">

<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-widgets-1.0.4.min.js"></script>

</head>
<body>
{{ script|safe }}
{{ div|safe }}
</body>
</html>

Я решил использовать простую синусоидальную волну в качестве примера данных для этого кода, но в реальной жизни я использую файл Excel (pd.read_excel) для проверки кода перед подключением веб-приложения к базе данных.

В коде Python, если я заменю

script, div = components(column(p, widgetbox(data_table))

с

script, div = components(p)

код работает отлично. Таким образом, это наводит меня на мысль, что проблема заключается в встраивании виджета или компоновки графиков и виджетов. Заранее благодарим за любую помощь, которую вы можете оказать.

Ответы [ 2 ]

1 голос
/ 25 марта 2019

За что я понял, я понял, что не так с моим исходным кодом. Очевидно, что нужно использовать ссылки на CSS и JS для таблиц bokeh при использовании DataTables с компонентами. Ниже приведены соответствующие ссылки и теги скрипта.

<link
    href="http://cdn.pydata.org/bokeh/release/bokeh-tables-1.0.4.min.css"
    rel="stylesheet" type="text/css">

<script src="http://cdn.pydata.org/bokeh/release/bokeh-tables-1.0.4.min.js"></script>
0 голосов
/ 22 марта 2019

Код ниже правильно отображает график и таблицу для Bokeh v1.0.4

import numpy as np
import pandas as pd
import webbrowser
from flask import Flask, render_template
from tornado.ioloop import IOLoop
from bokeh.application import Application
from bokeh.application.handlers import FunctionHandler
from bokeh.embed import server_document
from bokeh.models import ColumnDataSource
from bokeh.plotting import figure
from bokeh.models.widgets import DataTable, TableColumn
from bokeh.server.server import Server
from bokeh.layouts import column

app = Flask(__name__)
port = 5001

def get_plot(doc):
    x = np.linspace(0, 2, 1000)
    y = np.sin(x)
    df = pd.DataFrame({"x": x, "y":y})  # Not sure how to provide sample data

    def get_plot():
        p = figure()
        p.scatter(df['x'], df['y'])
        data_source = ColumnDataSource(df)
        columns = [ TableColumn(field = "field1", title = "Field 1"),
                    TableColumn(field = "field2", title = "Field 2"),
                    TableColumn(field = "field3", title = "Field 3"), ]
        data_table = DataTable(source = data_source, columns = columns)

        return column(p, data_table)

    doc.add_root(get_plot())
    doc.title = "Flask App Plot"

bokeh_app = Application(FunctionHandler(get_plot))

@app.route('/', methods = ['GET'])
def index():
    script = server_document('http://localhost:5006/bkapp')
    return render_template("index.html", script = script)

def bk_worker():
    server = Server({'/bkapp': bokeh_app}, io_loop = IOLoop(), allow_websocket_origin = ["localhost:{}".format(port)], port = port)
    server.start()
    server.io_loop.start()

from threading import Thread
Thread(target = bk_worker).start()

if __name__ == '__main__':
    print('Opening single process Flask app with embedded Bokeh application on http://localhost:{}/'.format(port))
    webbrowser.open_new("http://localhost:{}/".format(port))
    app.run(port = port, debug = False)

Результат:

enter image description here

...