【问题标题】:How to display a pandas dataframe as datatable?如何将熊猫数据框显示为数据表?
【发布时间】:2018-07-15 07:18:06
【问题描述】:

我想以DataTable 的形式显示一个表格 - 这是一个 pandas 数据框。在下面的简化示例中,我读取了用户提供的两个数字,它们确定了表格的行号和列号。该表的元素数量随后会正确显示,但是该表没有出现。

我认为问题在于我以错误的方式传递表格。当我尝试时

return jsonify(number_elements=a * b,
                   my_table=df)

我得到了错误

anaconda2/lib/python2.7/json/encoder.py",第 184 行,默认 raise TypeError(repr(o) + " is not JSON serializable")

类型错误:0 1 2 3 0 51 35 10 84 1 30 60 79 24 不是 JSON 可序列化

如果我使用

return jsonify(number_elements=a * b,
                   my_table=df.to_json())

那么没有错误但表格仍然没有显示。

我该如何正确地做到这一点?

我的index.html 文件如下所示:

<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
    <link href="https://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css"
          rel="stylesheet">
     <link href="https://cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css"
           rel="stylesheet">
  <script type=text/javascript>
    $(function() {
      $('a#calculate').bind('click', function() {
        $.getJSON('/_get_table', {
          a: $('input[name="a"]').val(),
          b: $('input[name="b"]').val()
        }, function(data) {
          $("#elements").text(data.number_elements);
          $("#a_nice_table").DataTable(data.my_table);
        });
        return false;
      });
    });
  </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <h3 class="text-muted">Create a pretty table</h3>
      </div>

      <div>
        <p>Number of rows</p>
        <input type="text" size="5" name="a" value="2">
        <p>Number of columns</p>
        <input type="text" size="5" name="b" value="4">

        <p><a href="javascript:void();" id="calculate">get a pretty table</a></p>
         <p>Result</p>
        <p>Number of elements:</p>
          <span id="elements">Hallo</span><br>
          <span id="a_nice_table">Here should be a table</span>
      </div>
    </div>
  </body>
</html>

我的文件app.py 看起来像这样:

from flask import Flask, render_template, request, jsonify
import pandas as pd
import numpy as np

# Initialize the Flask application
app = Flask(__name__)


@app.route('/')
def index():
    return render_template('index.html')


@app.route('/_get_table')
def get_table():
    a = request.args.get('a', type=int)
    b = request.args.get('b', type=int)

    df = pd.DataFrame(np.random.randint(0, 100, size=(a, b)))

    return jsonify(number_elements=a * b,
                   my_table=df)


if __name__ == '__main__':
    app.run(debug=True)

【问题讨论】:

    标签: python jquery pandas flask datatables


    【解决方案1】:

    这是我的实现。我做了一些优化,比如将你的 js 文件移动到 HTML 的末尾:

    index.html

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <link href="https://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet">
        <link href="https://cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css" rel="stylesheet">
      </head>
      <body>
        <div class="container">
          <div class="header">
            <h3 class="text-muted">Create a pretty table</h3>
          </div>
    
          <div>
            <p>Number of rows</p>
            <input type="text" size="5" name="a" value="2">
            <p>Number of columns</p>
            <input type="text" size="5" name="b" value="4">
    
            <p><a href="javascript:void();" id="calculate">get a pretty table</a></p>
             <p>Result</p>
            <p>Number of elements:</p>
              <span id="elements">Hallo</span><br>
              <table id="a_nice_table">Here should be a table</table>
          </div>
        </div>
        <script src="https://code.jquery.com/jquery-1.12.4.js" type="text/javascript"></script>
        <script src="https://cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js" type="text/javascript"></script>
        <script type="text/javascript">
          $(document).ready(function() {
            var table = null;
            $('a#calculate').bind('click', function() {
              $.getJSON('/_get_table', {
                a: $('input[name="a"]').val(),
                b: $('input[name="b"]').val()
              }, function(data) {
                $("#elements").text(data.number_elements);
                if (table !== null) {
                  table.destroy();
                  table = null;
                  $("#a_nice_table").empty();
                }
                table = $("#a_nice_table").DataTable({
                  data: data.my_table,
                  columns: data.columns
                });
              });
              return false;
            });
          });
        </script>
      </body>
    </html>
    

    app.py

    from flask import Flask, render_template, request, jsonify
    import pandas as pd
    import numpy as np
    import json
    
    # Initialize the Flask application
    app = Flask(__name__)
    
    
    @app.route('/')
    def index():
        return render_template('index.html')
    
    
    @app.route('/_get_table')
    def get_table():
        a = request.args.get('a', type=int)
        b = request.args.get('b', type=int)
    
        df = pd.DataFrame(np.random.randint(0, 100, size=(a, b)))
    
        return jsonify(number_elements=a * b,
                       my_table=json.loads(df.to_json(orient="split"))["data"],
                       columns=[{"title": str(col)} for col in json.loads(df.to_json(orient="split"))["columns"]])
    
    
    if __name__ == '__main__':
        app.run(debug=True)
    

    我修改了什么:

    1. 添加了js文件来渲染DataTable。
    2. 将 js 文件移至 HTML 的底部。
    3. 在 js 中添加了一个检查,用于在使用新数据刷新数据时销毁和清除列。
    4. 使用to_json方法,方向为split,为DataTables生成json数据。
    5. 还必须添加一个columns json 字符串供DataTables 使用,使用to_json 后动态设置

    下面是使用panda的to_html生成表格的方法:

    index.html

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <link href="https://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet">
        <link href="https://cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css" rel="stylesheet">
      </head>
      <body>
        <div class="container">
          <div class="header">
            <h3 class="text-muted">Create a pretty table</h3>
          </div>
    
          <div>
            <p>Number of rows</p>
            <input type="text" size="5" name="a" value="2">
            <p>Number of columns</p>
            <input type="text" size="5" name="b" value="4">
    
            <p><a href="javascript:void();" id="calculate">get a pretty table</a></p>
             <p>Result</p>
            <p>Number of elements:</p>
              <span id="elements">Hallo</span><br>
              <div id="mytablediv">Here should be a table</div>
          </div>
        </div>
        <script src="https://code.jquery.com/jquery-1.12.4.js" type="text/javascript"></script>
        <script src="https://cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js" type="text/javascript"></script>
        <script type="text/javascript">
          $(document).ready(function() {
            var table = null;
            $('a#calculate').bind('click', function() {
              $.getJSON('/_get_table', {
                a: $('input[name="a"]').val(),
                b: $('input[name="b"]').val()
              }, function(data) {
                $("#elements").text(data.number_elements);
                if (table !== null) {
                  table.destroy();
                  table = null;
                  $("#a_nice_table").empty();
                }
                $("#mytablediv").html(data.my_table);
                table = $("#a_nice_table").DataTable();
              });
              return false;
            });
          });
        </script>
      </body>
    </html>
    

    app.py

    from flask import Flask, render_template, request, jsonify
    import pandas as pd
    import numpy as np
    
    # Initialize the Flask application
    app = Flask(__name__)
    
    
    @app.route('/')
    def index():
        return render_template('index2.html')
    
    
    @app.route('/_get_table')
    def get_table():
        a = request.args.get('a', type=int)
        b = request.args.get('b', type=int)
    
        df = pd.DataFrame(np.random.randint(0, 100, size=(a, b)))
    
        return jsonify(number_elements=a * b,
                       my_table=df.to_html(classes='table table-striped" id = "a_nice_table',
                                           index=False, border=0))
    
    
    if __name__ == '__main__':
        app.run(debug=True)
    

    与之前实现的区别:

    1. 在 HTML 中,我必须添加一个父 div 以保存生成的 HTML 表。在这种情况下,我称之为mytablediv
    2. 在JS端的HTML中,我生成数据后基本要修改mytablediv的HTML内容。此 HTML 内容来自 to_html 输出。
    3. 在 JS 端的 HTML 中,我不必再将数据传递给 DataTable 函数,因为这将由 HTML 代码处理。
    4. app.py 中,我不得不对pandas 使用hackey 方法来生成HTML ID 标签。 ID 标签让 JS 知道要修改什么元素。我使用了here的解决方案。
    5. app.py 中,因为我现在正在生成 HTML,所以我还必须明确指定其他表格样式选项,例如 border=0index=False 以模仿以前的实现。

    【讨论】:

    • 效果很好,谢谢(暂时赞成;我会尝试了解发生了什么然后接受)!这是最好的方法还是会有更简单的解决方案(使用这些忍者模板)?
    • @Cleb 另一种方法是创建 HTML,正如@Arnaud 指出的那样,但我认为它与使用 to_json 没有什么不同,除了在几个地方更改了 javascript。另外,我更改的另一件事是您的 HTML 元素从 span 到 table。如果您打算使用引导程序设置表格样式,那么您可以执行以下操作:&lt;table id="a_nice_table" class="table table-striped"&gt;Here should be a table&lt;/table&gt;
    • 好的,谢谢。我不得不承认,我对这一切的了解相当有限。所以我真的不知道如何以及在哪里创建 html(因为表格可以有不同的尺寸)。如果这对您来说没有太多工作,如果您可以添加它会很棒,否则我也可以在某个时候提出另一个问题。感谢您对表格布局的建议;会试试的!
    • @Cleb 我将 HTML 实现添加到我的答案中:)
    • 非常感谢。我现在使用它并且像魅力一样工作。
    【解决方案2】:

    你不应该先生成一个html 表吗?利用pandas.DataFrame.to_html() 功能?事实上,documentation of DataTables 展示了一个使用 html 表格的示例。

    【讨论】:

    • 那我在哪里生成这个 html 表呢? my_table=df.to_html() 不起作用。
    • 是的,之前没注意这个。现在将:)。感谢您的反馈。
    猜你喜欢
    • 2019-04-05
    • 2018-02-28
    • 1970-01-01
    • 2015-06-11
    • 2019-10-12
    • 1970-01-01
    • 1970-01-01
    • 2018-03-25
    • 2017-08-26
    相关资源
    最近更新 更多