Display tables in Dash


#1

The code snippet below creates a line graph that reacts on the choice in a dropdown. Is there a way to display a table instead?


@app.callback(Output(‘my-graph’, ‘figure’), [Input(‘my-dropdown’, ‘value’)])
def update_graph(selected_dropdown_value):
df1 = df[(df[‘Förvaltningsnamn’] == selected_dropdown_value) & (df[‘År’] < now.year)]
df2 = df[(df[‘Förvaltningsnamn’] == comparison) & (df[‘År’] < now.year)]

trace = go.Scatter(x=df1.År, y=df1['Utfall%'] * 100, name=selected_dropdown_value)
trace1 = go.Scatter(x=df2.År, y=df2['Utfall%'] * 100, name=comparison)
x_axis = dict(nticks=len(df1.År),
              title='År'
             )
y_axis = dict(title='Utfall/Budget (%)')
layout = go.Layout(xaxis=x_axis, yaxis=y_axis, showlegend=True, legend=dict(orientation="h"))
data = [trace, trace1]
fig = go.Figure(data=data, layout=layout)
return fig

app.layout = html.Div([
html.Div([
dcc.Dropdown(
id=‘my-dropdown’,
options=[{‘label’: i, ‘value’: i}
for i in labels],
value=None
),
dcc.Graph(id='my-graph)
], style={‘width’: ‘49%’, ‘display’: ‘inline-block’, ‘padding’: ‘0 20’}),
html.Div([dcc.Graph(id=‘my-graph1’)], style={‘width’: ‘49%’, ‘display’: ‘inline-block’, ‘padding’: ‘0 20’})
])


#2

There is. See the example in the getting started guide at https://plot.ly/dash/getting-started that converts a pandas dataframe to an HTML table. Your callback can have the output Output('my-table-id', 'children') instead of Output('my-graph-id', 'figure').


#3

I’d recommend just creating a Plot.ly table as a figure. Refer to the help section below:


#4

@kejohns19 Does it work? This seams to be a perfect solution. Does dash need it’s own dcc.Table component then?


#5

@chriddyp thank you for the quick answer.
I am a beginner so it took me some time to figure it out. But now it works.:grinning:

@kejohns19 I tried to create a table based on a pandas dataframe with that guide. But I could not get it to work.

If someone else have the same problem maybe the explaination below can help you.
I copied the generate_table function from the link that @chriddyp provided. Below is a code snippet from my app,layout and the corresponding callback:

html.Div([html.H4(children='Chef'), html.Table(id='my-table')], style={'width': '49%','display': 'inline-block', 'padding': '0 20'})
#############################################################
@app.callback(Output('my-table', 'children'), [Input('my-dropdown', 'value')])
def table_update(selected_dropdown_value):
    df1 = dfChef[dfChef['Förvaltningsnamn'] == selected_dropdown_value]
    return generate_table(df1)

#6

How would you do this in Dash? I don’t see any mention of table in dash core components. Or should we still just call dcc.Graph(id=‘table’)?


#7

yes it worked - ploy.ly treats the table as a figure so just use the dash figure components.


#8

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)


#9

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.


#10

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])


#11

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)]).


#12

@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)

Interactivity between dependent dropdowns
#13

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.


Interactive Dash Tables
#14

@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!


#15

@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!


#16

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)


#18

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.


#19

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"})

#20

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())

#21

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.