How to show a pandas dataframe into a existing flask html table?

Question:

This may sound a noob question, but I’m stuck with it as Python is not one of my best languages.

I have a html page with a table inside it, and I would like to show a pandas dataframe in it.
What is the best way to do it? Use pandasdataframe.to_html?

py

from flask import Flask;
import pandas as pd;
from pandas import DataFrame, read_csv;

file = r'C:UsersmyuserDesktopTest.csv'
df = pd.read_csv(file)
df.to_html(header="true", table_id="table")

html

<div class="table_entrances" style="overflow-x: auto;">

  <table id="table">

    <thead></thead> 
    <tr></tr>

  </table>

</div>
Asked By: Motta

||

Answers:

# Declare table
class SomeTable(Table):
    status = Col('Customer')
    city = Col('City')
    product_price = Col('Country')    

# Convert the pandas Dataframe into dictionary structure
output_dict = output.to_dict(orient='records')  

# Populate the table
table = SomeTable(output_dict)

return (table.__html__())

or as pandas return static HTML file you can render it as page using Flask

@app.route('/<string:filename>/')
def render_static(filename):
    return render_template('%s.html' % filename)

It’s the Idea of how we can do it in Flask. Hope you can understand this and let me know if it’s not helping!

Update:

import pandas as pd

df = pd.DataFrame({'col1': ['abc', 'def', 'tre'],
                   'col2': ['foo', 'bar', 'stuff']})


from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello_world():
    return df.to_html(header="true", table_id="table")

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

Output

But I’d go with Flask HTML feature rather than DataFrame to HTML (due to styling)

Answered By: Chandu codes

working example:

python code:

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


app = Flask(__name__)

df = pd.DataFrame({'A': [0, 1, 2, 3, 4],
                   'B': [5, 6, 7, 8, 9],
                   'C': ['a', 'b', 'c--', 'd', 'e']})


@app.route('/', methods=("POST", "GET"))
def html_table():

    return render_template('simple.html',  tables=[df.to_html(classes='data')], titles=df.columns.values)



if __name__ == '__main__':
    app.run(host='0.0.0.0')

html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

{% for table in tables %}
            {{titles[loop.index]}}
            {{ table|safe }}
{% endfor %}
</body>
</html>

or else use

return render_template('simple.html',  tables=[df.to_html(classes='data', header="true")])

and remove {{titles[loop.index]}} line from html

if you inspect element on html

<html lang="en"><head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body style="">


            <table border="1" class="dataframe data">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>A</th>
      <th>B</th>
      <th>C</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>0</td>
      <td>5</td>
      <td>a</td>
    </tr>
    <tr>
      <th>1</th>
      <td>1</td>
      <td>6</td>
      <td>b</td>
    </tr>
    <tr>
      <th>2</th>
      <td>2</td>
      <td>7</td>
      <td>c--</td>
    </tr>
    <tr>
      <th>3</th>
      <td>3</td>
      <td>8</td>
      <td>d</td>
    </tr>
    <tr>
      <th>4</th>
      <td>4</td>
      <td>9</td>
      <td>e</td>
    </tr>
  </tbody>
</table>


</body></html>

as you can see it has tbody and thead with in table html. so you can easily apply css.

Answered By: Nihal

For me using Jinja’s for loop

{% for table in tables %}
            {{titles[loop.index]}}
            {{ table|safe }}
{% endfor %}

didnt work as it simply printed each character 1 by 1. I simply had to use

{{ table|safe }}
Answered By: Biarys

In case anyone finds this helpful. I have gone with an alternative because I needed more customization, including the ability to add buttons in the table that performed actions. I also really don’t like the standard table formatting as it is very ugly IMHO.

...

df = pd.DataFrame({'Patient Name': ["Some name", "Another name"],
                       "Patient ID": [123, 456],
                       "Misc Data Point": [8, 53]})
...

# link_column is the column that I want to add a button to
return render_template("patient_list.html", column_names=df.columns.values, row_data=list(df.values.tolist()),
                           link_column="Patient ID", zip=zip)

HTML Code: This Dynamically Converts any DF into a customize-able HTML table

<table>
    <tr>
        {% for col in column_names %}
        <th>{{col}}</th>
        {% endfor %}
    </tr>
    {% for row in row_data %}
    <tr>
        {% for col, row_ in zip(column_names, row) %}
        {% if col == link_column %}
        <td>
            <button type="submit" value={{ row_ }} name="person_id" form="patient_form" class="patient_button">
                {{ row_ }}
            </button>
        </td>
        {% else %}
        <td>{{row_}}</td>
        {% endif %}
        {% endfor %}
    </tr>
    {% endfor %}

</table>

CSS Code

table {
    font-family: arial, sans-serif;
    border-collapse: collapse;
    width: 100%;
}

td, th {
    border: 1px solid #dddddd;
    text-align: left;
    padding: 8px;
}

tr:nth-child(even) {
    background-color: #dddddd;
}

It performs very well and it looks WAY better than the .to_html output.

Answered By: Chris Farr

For those looking for a simple/succinct example of taking a Pandas df and turning into a Flask/Jinja table (which is the reason I ended up on this question):

APP.PY — APPLICATION FACTORY:

## YOUR DF LOGIC HERE 

@app.route("/")
def home():
    return render_template('index.html' column_names=df.columns.values, row_data=list(df.values.tolist()), zip=zip)

Your static template (e.g. index.html)

 <table>
        <thead>

          <tr>
            {% for col in column_names %}
            <th>
            
              {{col}}
             
            </th>
            {% endfor %}
          </tr>

        </thead>
        <tbody>
          {% for row in row_data %}
          <tr>
            {% for col, row_ in zip(column_names, row) %}
            <td>{{row_}}</td>
            {% endfor %}
          </tr>
          {% endfor %}

         
        </tbody>
  
      </table>
   
Answered By: mikelowry

If you’ve invested time and effort in mastering Panda’s dataframe styling (perhaps in the context of Jupyter), then you may want to preserve as much of that as possible when you present a dataframe in Flask.

If so, here are the relevant bits of code:

In your controller:

someDataTable = [styledDataFrame.to_html(classes='data', header="true")]

So let’s say styledDataFrame was something like this:

styledDataFrame = someDF.style.set_table_styles([dict(selector='th', props=[('text-align', 'center')])])
        .hide(axis='index')
        .format(precision=1, thousands=",")

Okay, okay, maybe not the most amazing layout – but let’s assume we like it, and want Flask to display basically what we see in Jupyter.

So then (still in the controller):

return render_template(
    'dataViewer.html',
    someNiceMetaData=someNiceMetaData,
    sampleDataTable=sampleDataTable
)

And then in your template (which in this scenario would be called dataViewer.html):

{% block sampledata %}
    <h3>Sample Data</h3>

     {% for table in sampleDataTable %}
        {{ table | safe }}
    {% endfor %}

{% endblock %}

In this way you can continue to enrich your dataframe styler in Jupyter, and simply pass your best ideas through to Flask.

This approach is particularly compelling if, like me, you know way less about CSS than you do about Pandas, and you actually like the Pandas styler! (just me? Come on, the Pandas styler is really cool!)

Answered By: James_SO