Black Lives Matter. Please consider donating to Black Girls Code today.

Display tables in Dash

You still return a figure to dcc.Graph - it is simply that the figure is a table. I ended up creating a table and graph as one figure and passing that to dcc.Graph based off of the the plot.ly tables with graphs example (https://plot.ly/python/table/#tables-with-graphs)

Thanks. It’s still beyond my tiny brain unfortunately. Just can’t translate the tables tutorial into Dash (whether to use ff.create_table, etc). No worries if you can’t help - will get there in the end.

Will, you can cut and paste this example into your app.layout call:

html.Table(
    [
        html.Tr( [html.Th("name"), html.Th("address"), html.Th("email")] )
    ] +
    [
        html.Tr( [html.Td("walter"), html.Td("rudin"), html.Td("wr@analysis.com")] ),
        html.Tr( [html.Td("gilbert"), html.Td("strang"), html.Td("gb@algebra.com")] )
    ]
)

What got me was the + sign. To me, it was intuitive to send two arguments ([table_header_row], [data_rows]), but you should not do this. You need to do ([table_header_row] + [data_rows])

If you have a pandas dataframe (df) create a figure object such as fig = ff.create_table(df). Then create the dash app with: app.layout = html.Div([dcc.Graph(fig)]).

1 Like

@htp84 - Here’s how you can use the generate_table function in a callback:

app.layout = html.Div([
    dcc.Dropdown(id='my-dropdown'), # fill this in
    html.Div(id='table-container')
])

@app.callback(Output('table-container', 'children'), [Input('my-dropdown', 'value')])
def update_table(value):
    dff = df[df['some-column'] == value] # update with your own logic
    return generate_table(dff)
3 Likes

To summarize the solutions that are available right now:

Solution 1 - Native HTML Table

This renders a table using native HTML elements, that is: Table, Tr, Th. See the generate_table function in https://plot.ly/dash/getting-started for a little recipe that converts a dataframe to standard HTML table. You can modify the style of this table with CSS.

Directly inside the layout, this would look like:

app.layout = html.Div([
    generate_table(df)
])

Or, inside a callback:

app.layout = html.Div([
    dcc.Dropdown(id='my-dropdown'), # fill this in
    html.Div(id='table-container')
])

@app.callback(Output('table-container', 'children'), [Input('my-dropdown', 'value')])
def update_table(value):
    dff = df[df['some-column'] == value] # update with your own logic
    return generate_table(dff)

Solution 2 - Plotly Table

The Plotly-Python library has a FigureFactory function that generates a table using the underlying heatmap trace type. The docs for this are here: https://plot.ly/python/table/

You would use this in Dash through the Graph component, so:

import plotly.figure_factory as ff

figure = ff.create_table(...) # see docs https://plot.ly/python/table/
app.layout = html.Div([
    dcc.Graph(id='my-table', figure=figure)
])

or in a callback like:

app.layout = html.Div([
    [...]
    dcc.Dropdown(id='my-dropdown', [...]),
    dcc.Graph(id='my-table')
])

@app.callback(Output('my-table', 'figure'), [Input('my-dropdown', 'value')])
def update_table(value):
    dff = df[df['filter-column'] == value] # replace with your own data processing code
    new_table_figure = ff.create_table(dff)
    return new_table_figure

Solution 3 - Wait for new official plotly.js table trace type

The figure_factory in Solution 2 creates a table-like graph by using an underlying heatmap. The plotly.js team is adding an official table “chart type”, see https://github.com/plotly/plotly.js/pull/1834. This table component will expose all of the styling properties directly (instead of through CSS) which will make it easier to style.

Solution 4 - Build Your Own (or contract us to)

If you need more table features that aren’t available above, you can either build your own dash component or contract out our advanced development team.

11 Likes

@chriddyp Thanks for the answer and the guide. I really appreciate that you took time to write the guide.Although, as i mentioned in my latest post (sorry, did not respond to your answer), I got the generate_table function to work, but not the figure factory solution. But I see that you have provided a guide for that too. I’ll have a go at that solution to. Thanks!

1 Like

@chriddyp Thank you for the guide. I am able to create table with both methods. However the native HTML table I created looks different with the one in the “getting-started” page. My table is just a bunch of numbers arranged like a table, without any grid lines. I am wondering if you have any thoughts why that would happen.

I also have a suggestion. It seems to me that Dash is focused on plots. However in my opinion table is also very important in a dashboard report or application. There are disadvantages to treat table as figure using plotly, especially if the table is relatively big. It would be great if Dash could support table display like the one in jupyter notebook or jupyterlab. Thanks!

Anyone tried making tables using Markdown and showing them that way?
I have tried using this code and having it set a dcc.Markdown.children. I have also tried having it return a dcc.Markdown to a html.Div.children but both rendered the table as free text.

def df_to_markdown_table(df):
""“
Converts dataframe to markdown for Dash rendering
:param df:
:return:
Taken from https://stackoverflow.com/questions/33181846/programmatically-convert-pandas-dataframe-to-markdown-table
>>> t_df = pd.DataFrame([dict(a = 1, b = “kevin”)])
>>> print(df_to_markdown_table(t_df))
a|b
—|---
1|kevin

”"“
from IPython.display import Markdown, display
fmt = [’—’ for i in range(len(df.columns))]
df_fmt = pd.DataFrame([fmt], columns=df.columns)
df_formatted = pd.concat([df_fmt, df])
return df_formatted.to_csv(sep=”|", index=False)

Hi KevinM.

I looked into tables in markdown. Officially, Dash uses the CommonMark spec for markdown, which, to my knowledge, does not support tables, although users have requested it. I’d just stick with options 1 or 2 that chriddy posted above. Or 3 or 4, depending. :smiley:

Of the 2 options mentioned above, I prefer the html method. The reason I don’t like Plotly Table method is that it creates a heatmap that looks like a bunch of table rows and columns, and it overlays your data to make it look like a table. This means that you can zoom in on the table in a way that doesn’t seem intuitive. You could probably just turn off the controls and that would fix this. But html seems more natural fit for Dash.

The upside to using the Plotly Table is that you can use LaTex in your rows/columns. There are probably other advantages that I am not aware of.

1 Like

You’ll need to add CSS to style your table in the same way. There was a note about this in the docs although it was easy to miss :slight_smile:

Here is the line you need to style your table in the exact same way:

app.css.append_css({"external_url": "https://codepen.io/chriddyp/pen/bWLwgP.css"})

What I ended up doing and which I haven’t seen mentioned here yet is to use the pandas.DataFrame.to_html(…) method and put that in an Iframe.

def create_table(df):
    return html.Iframe(srcDoc=df.to_html())
3 Likes

It will great to provide an example with a library such as Blaze http://blaze.pydata.org/ to show how to display a table in Dash without fetching all data to memory at startup.

I have started working on an official (editable) Table component here: https://github.com/plotly/dash-table-experiments. It will eventually get merged into dash-core-components when it becomes stable.

4 Likes

Thanks @chriddyp for the great work.
But what is your opinion about avoiding fetching all data into memory at startup.
You should create a fake big table into a database to see how it scale.


is for example able of displaying a chunk of a database table without fetching content of the whole table to memory (it’s using Blaze to achieve this)

This sounds like a problem that the dash developer should solve rather than the Table component should solve. The Dash developer can solve this by making queries that limit the number of results and/or building a UI that queries more data if necessary. The Table component itself won’t fetch or query data in the python context. The Table component could help out the user in building this UI by providing attributes for pagination, which could be Input elements in a callback that would query more data.

I will likely make the table performant so that passing in a huge dataframe “just works”. However, rendering a table with more than a thousand rows isn’t a useful experience without search, filtering, or ordering capabilities.

1 Like

Made some more progress on a supercharged table component tonight. It is now sortable and filterable. See for more: https://github.com/plotly/dash-table-experiments

import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_table_experiments as dt
import json
import pandas as pd
import numpy as np

app = dash.Dash()

app.scripts.config.serve_locally=True

DF_WALMART = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/1962_2006_walmart_store_openings.csv')

app.layout = html.Div([
    html.H4('DataTable'),
    dt.DataTable(
        dataframe=DF_WALMART.to_dict('split'),
        filterable=True,
        sortable=True
    )
])

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

4 Likes

Hi, could you also share how you declared the dropdown? I need to create a dropdown that, based on selection, populates my pandas table.

Could you create a new thread for this question? I also recommend reading through the user guide at https://plot.ly/dash/getting-started and https://plot.ly/dash/getting-started-part-2.

Hi Chris,

So cool to interact with you.

I will start a new thread.

Been playing with the dash-table-experiment as it does some of what I need.

Thanks, Jorge