Pandas Dataframe display on a webpage
Question:
I am using Flask but this probably applies to a lot of similar frameworks.
I construct a pandas Dataframe, e.g.
@app.route('/analysis/<filename>')
def analysis(filename):
x = pd.DataFrame(np.random.randn(20, 5))
return render_template("analysis.html", name=filename, data=x)
The template analysis.html looks like
{% extends "base.html" %}
{% block content %}
<h1>{{name}}</h1>
{{data}}
{% endblock %}
This works but the output looks horrible. It doesn’t use linebreaks etc.
I have played with data.to_html()
and data.to_string()
What’s the easiest way to display a frame?
Answers:
The following should work:
@app.route('/analysis/<filename>')
def analysis(filename):
x = pd.DataFrame(np.random.randn(20, 5))
return render_template("analysis.html", name=filename, data=x.to_html())
# ^^^^^^^^^
Check the documentation for additional options like CSS styling.
Additionally, you need to adjust your template like so:
{% extends "base.html" %}
{% block content %}
<h1>{{name}}</h1>
{{data | safe}}
{% endblock %}
in order to tell Jinja you’re passing in markup. Thanks to @SeanVieira for the tip.
Ok, I have managed to get some very nice results by now combining the hints I got here. In the actual Python viewer I use
@app.route('/analysis/<filename>')
def analysis(filename):
x = pd.DataFrame(np.random.randn(20, 5))
return render_template("analysis.html", name=filename, data=x)
e.g. I send the complete dataframe to the html template. My html template is based on bootstrap. Hence I can simply write
{% extends "base.html" %}
{% block content %}
<h1>{{name}}</h1>
{{ data.to_html(classes="table table-striped") | safe}}
{% endblock %}
There are numerous other options with bootstrap, check out here:
http://getbootstrap.com/css/#tables
Base.html is essentially copied from here
http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-xii-facelift
The next question is obviously how to plot such a frame. Anyone any experience with Bokeh?
Thank you both to Matt and Sean.
thomas
You can use enaml-web to display and interact with pandas dataframes.
A few examples:
- With filtering – https://github.com/frmdstryr/smd-search
- Simple viewer – https://github.com/codelv/enaml-web/tree/master/examples/dataframe_viewer
Note: Interaction (sorting, filtering, etc…) requires a server with websocket support.
Iterating over the rows of a df
If you need to have the df
in a format that can iterate over the rows in your html, then use to_dict(orient='records')
, which produces a dict
in a format:
‘records’ : list like [{column -> value}, … , {column -> value}]
That way you can use your own way of displaying the data in your html.
The sample code would now look like this:
Python code using flask
@app.route('/analysis/<filename>')
def analysis(filename):
x = pd.DataFrame(np.random.randn(20, 5))
return render_template("analysis.html", name=filename, data=x.to_dict(orient='records'))
HTML code with jinja
{% extends "base.html" %}
{% block content %}
<table class="table">
<thead>
<tr>
<th scope="col">Column name 1</th>
<th scope="col">Column name 2</th>
<th scope="col">Column name 3</th>
</tr>
</thead>
<tbody>
{% for row in data %}
<tr>
<td>{{row['Column name 1']}}</td>
<td>{{row['Column name 2']}}</td>
<td>{{row['Column name 2']}}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
I am using Flask but this probably applies to a lot of similar frameworks.
I construct a pandas Dataframe, e.g.
@app.route('/analysis/<filename>')
def analysis(filename):
x = pd.DataFrame(np.random.randn(20, 5))
return render_template("analysis.html", name=filename, data=x)
The template analysis.html looks like
{% extends "base.html" %}
{% block content %}
<h1>{{name}}</h1>
{{data}}
{% endblock %}
This works but the output looks horrible. It doesn’t use linebreaks etc.
I have played with data.to_html()
and data.to_string()
What’s the easiest way to display a frame?
The following should work:
@app.route('/analysis/<filename>')
def analysis(filename):
x = pd.DataFrame(np.random.randn(20, 5))
return render_template("analysis.html", name=filename, data=x.to_html())
# ^^^^^^^^^
Check the documentation for additional options like CSS styling.
Additionally, you need to adjust your template like so:
{% extends "base.html" %}
{% block content %}
<h1>{{name}}</h1>
{{data | safe}}
{% endblock %}
in order to tell Jinja you’re passing in markup. Thanks to @SeanVieira for the tip.
Ok, I have managed to get some very nice results by now combining the hints I got here. In the actual Python viewer I use
@app.route('/analysis/<filename>')
def analysis(filename):
x = pd.DataFrame(np.random.randn(20, 5))
return render_template("analysis.html", name=filename, data=x)
e.g. I send the complete dataframe to the html template. My html template is based on bootstrap. Hence I can simply write
{% extends "base.html" %}
{% block content %}
<h1>{{name}}</h1>
{{ data.to_html(classes="table table-striped") | safe}}
{% endblock %}
There are numerous other options with bootstrap, check out here:
http://getbootstrap.com/css/#tables
Base.html is essentially copied from here
http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-xii-facelift
The next question is obviously how to plot such a frame. Anyone any experience with Bokeh?
Thank you both to Matt and Sean.
thomas
You can use enaml-web to display and interact with pandas dataframes.
A few examples:
- With filtering – https://github.com/frmdstryr/smd-search
- Simple viewer – https://github.com/codelv/enaml-web/tree/master/examples/dataframe_viewer
Note: Interaction (sorting, filtering, etc…) requires a server with websocket support.
Iterating over the rows of a df
If you need to have the df
in a format that can iterate over the rows in your html, then use to_dict(orient='records')
, which produces a dict
in a format:
‘records’ : list like [{column -> value}, … , {column -> value}]
That way you can use your own way of displaying the data in your html.
The sample code would now look like this:
Python code using flask
@app.route('/analysis/<filename>')
def analysis(filename):
x = pd.DataFrame(np.random.randn(20, 5))
return render_template("analysis.html", name=filename, data=x.to_dict(orient='records'))
HTML code with jinja
{% extends "base.html" %}
{% block content %}
<table class="table">
<thead>
<tr>
<th scope="col">Column name 1</th>
<th scope="col">Column name 2</th>
<th scope="col">Column name 3</th>
</tr>
</thead>
<tbody>
{% for row in data %}
<tr>
<td>{{row['Column name 1']}}</td>
<td>{{row['Column name 2']}}</td>
<td>{{row['Column name 2']}}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}