By default, the table will expand to the width of its container.
The width of the columns is determined automatically in order to
accommodate the content in the cells.
from dash import Dash, dash_table
import pandas as pd
from collections import OrderedDict
data = OrderedDict(
[
("Date", ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"]),
("Region", ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"]),
("Temperature", [1, -20, 3.512, 4, 10423, -441.2]),
("Humidity", [10, 20, 30, 40, 50, 60]),
("Pressure", [2, 10924, 3912, -10, 3591.2, 15]),
]
)
df = pd.DataFrame(data)
app = Dash()
app.layout = dash_table.DataTable(
data=df.to_dict('records'),
columns=[{'id': c, 'name': c} for c in df.columns]
)
if __name__ == '__main__':
app.run(debug=True)
The default styles work well for a small number of columns and short
text. However, if you are rendering a large number of columns or
cells with long contents, then you’ll need to employ one of the
following overflow strategies to keep the table within its container.
If your cells contain contain text with spaces, then you can overflow
your content into multiple lines.
style_cell
updates the styling for the data cells & the header cells.
To specify header styles, use style_header
.
To specify data cell styles, use style_data
.
This example keeps the header on a single line while wrapping the data cells.
from dash import Dash, dash_table
import pandas as pd
from collections import OrderedDict
data_election = OrderedDict(
[
(
"Date",
[
"July 12th, 2013 - July 25th, 2013",
"July 12th, 2013 - August 25th, 2013",
"July 12th, 2014 - August 25th, 2014",
],
),
(
"Election Polling Organization",
["The New York Times", "Pew Research", "The Washington Post"],
),
("Rep", [1, -20, 3.512]),
("Dem", [10, 20, 30]),
("Ind", [2, 10924, 3912]),
(
"Region",
[
"Northern New York State to the Southern Appalachian Mountains",
"Canada",
"Southern Vermont",
],
),
]
)
df = pd.DataFrame(data_election)
app = Dash()
app.layout = dash_table.DataTable(
style_data={
'whiteSpace': 'normal',
'height': 'auto',
},
data=df.to_dict('records'),
columns=[{'id': c, 'name': c} for c in df.columns]
)
if __name__ == '__main__':
app.run(debug=True)
If you are displaying lots of text in your cells, then you may want to
make the text appear a little more dense by shortening up the line-height.
By default (as above), it’s around 22px. Here, it’s 15px.
from dash import Dash, dash_table
import pandas as pd
from collections import OrderedDict
data_election = OrderedDict(
[
(
"Date",
[
"July 12th, 2013 - July 25th, 2013",
"July 12th, 2013 - August 25th, 2013",
"July 12th, 2014 - August 25th, 2014",
],
),
(
"Election Polling Organization",
["The New York Times", "Pew Research", "The Washington Post"],
),
("Rep", [1, -20, 3.512]),
("Dem", [10, 20, 30]),
("Ind", [2, 10924, 3912]),
(
"Region",
[
"Northern New York State to the Southern Appalachian Mountains",
"Canada",
"Southern Vermont",
],
),
]
)
df = pd.DataFrame(data_election)
app = Dash()
app.layout = dash_table.DataTable(
style_data={
'whiteSpace': 'normal',
'height': 'auto',
'lineHeight': '15px'
},
data=df.to_dict('records'),
columns=[{'id': c, 'name': c} for c in df.columns]
)
if __name__ == '__main__':
app.run(debug=True)
If your text is really long, then you can constrain the height of the
cells and display a tooltip when hovering over the cell.
from dash import Dash, dash_table
import pandas as pd
from collections import OrderedDict
moby_dick_text = [
'Call me Ishmael. ',
''.join([
'Some years ago- never mind how long precisely- having little or no money ',
'in my purse, and nothing particular to interest me on shore, ',
'I thought I would sail about a little and see the watery part of the world. ',
]),
'It is a way I have of driving off the spleen and regulating the circulation.'
]
moby_dick = OrderedDict(
[
(
'Sentence Number', [i+1 for i in range(len(moby_dick_text))],
),
(
'Text', [i for i in moby_dick_text]
)
]
)
df = pd.DataFrame(moby_dick)
app = Dash()
app.layout = dash_table.DataTable(
style_data={
'whiteSpace': 'normal',
},
data=df.to_dict('records'),
columns=[{'id': c, 'name': c} for c in df.columns],
css=[{
'selector': '.dash-spreadsheet td div',
'rule': '''
line-height: 15px;
max-height: 30px; min-height: 30px; height: 30px;
display: block;
overflow-y: hidden;
'''
}],
tooltip_data=[
{
column: {'value': str(value), 'type': 'markdown'}
for column, value in row.items()
} for row in df.to_dict('records')
],
tooltip_duration=None,
style_cell={'textAlign': 'left'} # left align text in columns for readability
)
if __name__ == '__main__':
app.run(debug=True)
Hover over the cells to see the tooltip.
Why the css
? Fixed height cells are tricky because, by CSS 2.1 rules,
the height of a table cell is “the minimum height required by the content”.
So, here we are setting the height of the cell indirectly
by setting the div within the cell.
In this example, we display two lines of data by setting the line-height
to be 15px and the height of each cell to be 30px.
The second sentence is cut off.
There are a few limitations with this method:
Subscribe to plotly/dash-table#737 for updates or other workarounds
on this issue.
Alternatively, you can keep the content on a single line but display
a set of ellipses if the content is too long to fit into the cell.
Here, max-width
is set to 0. It could be any number, the only
important thing is that it is supplied. The behaviour will be
the same whether it is 0 or 50.
If you want to just hide the content instead of displaying ellipses,
then set textOverflow
to 'clip'
instead of 'ellipsis'
.
from dash import Dash, dash_table
import pandas as pd
from collections import OrderedDict
data_election = OrderedDict(
[
(
"Date",
[
"July 12th, 2013 - July 25th, 2013",
"July 12th, 2013 - August 25th, 2013",
"July 12th, 2014 - August 25th, 2014",
],
),
(
"Election Polling Organization",
["The New York Times", "Pew Research", "The Washington Post"],
),
("Rep", [1, -20, 3.512]),
("Dem", [10, 20, 30]),
("Ind", [2, 10924, 3912]),
(
"Region",
[
"Northern New York State to the Southern Appalachian Mountains",
"Canada",
"Southern Vermont",
],
),
]
)
df = pd.DataFrame(data_election)
app = Dash()
app.layout = dash_table.DataTable(
data=df.to_dict('records'),
columns=[{'id': c, 'name': c} for c in df.columns],
style_cell={
'overflow': 'hidden',
'textOverflow': 'ellipsis',
'maxWidth': 0
}
)
if __name__ == '__main__':
app.run(debug=True)
In the example above, ellipsis are not displayed for the header.
We consider this a bug, subscribe to plotly/dash-table#735 for updates.
If you are display text data that is cut off by ellipses, then you can
include tooltips so that the full text appears on hover.
By setting tooltip_duration
to None
, the tooltip will persist
as long as the mouse pointer is above the cell, and it will disappear
when the pointer moves away. You can override this by passing in
a number in milliseconds (e.g. 2000 if you want it to disappear after
two seconds).
from dash import Dash, dash_table
import pandas as pd
from collections import OrderedDict
data_election = OrderedDict(
[
(
"Date",
[
"July 12th, 2013 - July 25th, 2013",
"July 12th, 2013 - August 25th, 2013",
"July 12th, 2014 - August 25th, 2014",
],
),
(
"Election Polling Organization",
["The New York Times", "Pew Research", "The Washington Post"],
),
("Rep", [1, -20, 3.512]),
("Dem", [10, 20, 30]),
("Ind", [2, 10924, 3912]),
(
"Region",
[
"Northern New York State to the Southern Appalachian Mountains",
"Canada",
"Southern Vermont",
],
),
]
)
df = pd.DataFrame(data_election)
app = Dash()
app.layout = dash_table.DataTable(
data=df.to_dict('records'),
columns=[{'id': c, 'name': c} for c in df.columns],
style_cell={
'overflow': 'hidden',
'textOverflow': 'ellipsis',
'maxWidth': 0,
},
tooltip_data=[
{
column: {'value': str(value), 'type': 'markdown'}
for column, value in row.items()
} for row in df.to_dict('records')
],
tooltip_duration=None
)
if __name__ == '__main__':
app.run(debug=True)
Instead of trying to fit all of the content in the container, you could
overflow the entire container into a scrollable container.
from dash import Dash, dash_table
import pandas as pd
from collections import OrderedDict
data_election = OrderedDict(
[
(
"Date",
[
"July 12th, 2013 - July 25th, 2013",
"July 12th, 2013 - August 25th, 2013",
"July 12th, 2014 - August 25th, 2014",
],
),
(
"Election Polling Organization",
["The New York Times", "Pew Research", "The Washington Post"],
),
("Rep", [1, -20, 3.512]),
("Dem", [10, 20, 30]),
("Ind", [2, 10924, 3912]),
(
"Region",
[
"Northern New York State to the Southern Appalachian Mountains",
"Canada",
"Southern Vermont",
],
),
]
)
df = pd.DataFrame(data_election)
app = Dash()
app.layout = dash_table.DataTable(
data=df.to_dict('records'),
columns=[{'id': c, 'name': c} for c in df.columns],
style_table={'overflowX': 'auto'},
)
if __name__ == '__main__':
app.run(debug=True)
Note how we haven’t explicitly set the width of the individual columns
yet. The widths of the columns have been computed dynamically depending
on the width of the table and the width of the cell’s contents.
In the example above, by providing a scrollbar, we’re effectively
giving the table as much width as it needs in order to fit the entire
width of the cell contents on a single line.
Alternatively, you can fix the width of each column by adding width
.
In this case, the column’s width will be constant, even if its contents
are shorter or wider.
from dash import Dash, dash_table
import pandas as pd
from collections import OrderedDict
data_election = OrderedDict(
[
(
"Date",
[
"July 12th, 2013 - July 25th, 2013",
"July 12th, 2013 - August 25th, 2013",
"July 12th, 2014 - August 25th, 2014",
],
),
(
"Election Polling Organization",
["The New York Times", "Pew Research", "The Washington Post"],
),
("Rep", [1, -20, 3.512]),
("Dem", [10, 20, 30]),
("Ind", [2, 10924, 3912]),
(
"Region",
[
"Northern New York State to the Southern Appalachian Mountains",
"Canada",
"Southern Vermont",
],
),
]
)
df = pd.DataFrame(data_election)
app = Dash()
app.layout = dash_table.DataTable(
data=df.to_dict('records'),
columns=[{'id': c, 'name': c} for c in df.columns],
style_table={'overflowX': 'auto'},
style_cell={
'height': 'auto',
# all three widths are needed
'minWidth': '180px', 'width': '180px', 'maxWidth': '180px',
'whiteSpace': 'normal'
}
)
if __name__ == '__main__':
app.run(debug=True)
from dash import Dash, dash_table
import pandas as pd
from collections import OrderedDict
data_election = OrderedDict(
[
(
"Date",
[
"July 12th, 2013 - July 25th, 2013",
"July 12th, 2013 - August 25th, 2013",
"July 12th, 2014 - August 25th, 2014",
],
),
(
"Election Polling Organization",
["The New York Times", "Pew Research", "The Washington Post"],
),
("Rep", [1, -20, 3.512]),
("Dem", [10, 20, 30]),
("Ind", [2, 10924, 3912]),
(
"Region",
[
"Northern New York State to the Southern Appalachian Mountains",
"Canada",
"Southern Vermont",
],
),
]
)
df = pd.DataFrame(data_election)
app = Dash()
app.layout = dash_table.DataTable(
data=df.to_dict('records'),
columns=[{'id': c, 'name': c} for c in df.columns],
style_table={'overflowX': 'auto'},
style_cell={
# all three widths are needed
'minWidth': '180px', 'width': '180px', 'maxWidth': '180px',
'overflow': 'hidden',
'textOverflow': 'ellipsis',
}
)
if __name__ == '__main__':
app.run(debug=True)
You can also add a horizontal scrollbar to your table by fixing
the leftmost columns with fixed_columns
.
from dash import Dash, dash_table
import pandas as pd
from collections import OrderedDict
data_election = OrderedDict(
[
(
"Date",
[
"July 12th, 2013 - July 25th, 2013",
"July 12th, 2013 - August 25th, 2013",
"July 12th, 2014 - August 25th, 2014",
],
),
(
"Election Polling Organization",
["The New York Times", "Pew Research", "The Washington Post"],
),
("Rep", [1, -20, 3.512]),
("Dem", [10, 20, 30]),
("Ind", [2, 10924, 3912]),
(
"Region",
[
"Northern New York State to the Southern Appalachian Mountains",
"Canada",
"Southern Vermont",
],
),
]
)
df = pd.DataFrame(data_election)
app = Dash()
app.layout = dash_table.DataTable(
data=df.to_dict('records'),
columns=[{'id': c, 'name': c} for c in df.columns],
fixed_columns={'headers': True, 'data': 1},
style_table={'minWidth': '100%'}
)
if __name__ == '__main__':
app.run(debug=True)
Here is the same example but with fixed-width cells & ellipses.
from dash import Dash, dash_table
import pandas as pd
from collections import OrderedDict
data_election = OrderedDict(
[
(
"Date",
[
"July 12th, 2013 - July 25th, 2013",
"July 12th, 2013 - August 25th, 2013",
"July 12th, 2014 - August 25th, 2014",
],
),
(
"Election Polling Organization",
["The New York Times", "Pew Research", "The Washington Post"],
),
("Rep", [1, -20, 3.512]),
("Dem", [10, 20, 30]),
("Ind", [2, 10924, 3912]),
(
"Region",
[
"Northern New York State to the Southern Appalachian Mountains",
"Canada",
"Southern Vermont",
],
),
]
)
df = pd.DataFrame(data_election)
app = Dash()
app.layout = dash_table.DataTable(
data=df.to_dict('records'),
columns=[{'id': c, 'name': c} for c in df.columns],
fixed_columns={ 'headers': True, 'data': 1 },
style_table={'minWidth': '100%'},
style_cell={
# all three widths are needed
'minWidth': '180px', 'width': '180px', 'maxWidth': '180px',
'overflow': 'hidden',
'textOverflow': 'ellipsis',
}
)
if __name__ == '__main__':
app.run(debug=True)
The widths of individual columns can be supplied through the
style_cell_conditional
property. These widths can be specified as
percentages or fixed pixels.
from dash import Dash, dash_table
import pandas as pd
from collections import OrderedDict
data = OrderedDict(
[
("Date", ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"]),
("Region", ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"]),
("Temperature", [1, -20, 3.512, 4, 10423, -441.2]),
("Humidity", [10, 20, 30, 40, 50, 60]),
("Pressure", [2, 10924, 3912, -10, 3591.2, 15]),
]
)
df = pd.DataFrame(data)
app = Dash()
app.layout = dash_table.DataTable(
data=df.to_dict('records'),
columns=[{'id': c, 'name': c} for c in df.columns],
style_cell_conditional=[
{'if': {'column_id': 'Date'},
'width': '30%'},
{'if': {'column_id': 'Region'},
'width': '30%'},
]
)
if __name__ == '__main__':
app.run(debug=True)
from dash import Dash, dash_table
import pandas as pd
from collections import OrderedDict
data = OrderedDict(
[
("Date", ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"]),
("Region", ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"]),
("Temperature", [1, -20, 3.512, 4, 10423, -441.2]),
("Humidity", [10, 20, 30, 40, 50, 60]),
("Pressure", [2, 10924, 3912, -10, 3591.2, 15]),
]
)
df = pd.DataFrame(data)
app = Dash()
app.layout = dash_table.DataTable(
data=df.to_dict('records'),
columns=[{'id': c, 'name': c} for c in df.columns],
style_cell_conditional=[
{'if': {'column_id': 'Date'},
'width': '30%'},
{'if': {'column_id': 'Region'},
'width': '30%'},
]
)
if __name__ == '__main__':
app.run(debug=True)
By default, the column width is the maximum of the percentage given
and the width of the content. So, if the content in the column is wide,
the column may be wider than the percentage given. This prevents overflow.
In the example below, note the first column is actually wider than 10%;
if it were shorter, the text “New York City” would overflow.
from dash import Dash, dash_table, html
import pandas as pd
from collections import OrderedDict
data = OrderedDict(
[
("Date", ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"]),
("Region", ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"]),
("Temperature", [1, -20, 3.512, 4, 10423, -441.2]),
("Humidity", [10, 20, 30, 40, 50, 60]),
("Pressure", [2, 10924, 3912, -10, 3591.2, 15]),
]
)
df = pd.DataFrame(data)
app = Dash()
app.layout = html.Div([
html.Div('10%', style={'backgroundColor': 'hotpink', 'color': 'white', 'width': '10%'}),
dash_table.DataTable(
data=df.to_dict('records'),
columns=[{'id': c, 'name': c} for c in df.columns if c != 'Date'],
style_cell_conditional=[
{'if': {'column_id': 'Region'},
'width': '10%'}
]
)
])
if __name__ == '__main__':
app.run(debug=True)
To force columns to be a certain width (even if that causes overflow)
use table-layout: fixed
.
table-layout: fixed
If you want all columns to have the same percentage-based width,
use style_data
and table-layout: fixed
.
from dash import Dash, dash_table
import pandas as pd
from collections import OrderedDict
data = OrderedDict(
[
("Date", ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"]),
("Region", ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"]),
("Temperature", [1, -20, 3.512, 4, 10423, -441.2]),
("Humidity", [10, 20, 30, 40, 50, 60]),
("Pressure", [2, 10924, 3912, -10, 3591.2, 15]),
]
)
df = pd.DataFrame(data)
app = Dash()
app.layout = dash_table.DataTable(
data=df.to_dict('records'),
columns=[{'id': c, 'name': c} for c in df.columns],
css=[{'selector': 'table', 'rule': 'table-layout: fixed'}],
style_cell={
'width': '{}%'.format(len(df.columns)),
'textOverflow': 'ellipsis',
'overflow': 'hidden'
}
)
if __name__ == '__main__':
app.run(debug=True)
Setting consistent percentage-based widths is a good option if you are using
virtualization
, sorting (sort_action
), or filtering
(filter_action
).
Without fixed column widths, the table will dynamically resize the
columns depending on the width of the data that is displayed.
Limitations
fixed_rows
& table-layout: fixed
.fixed_rows
and without table-layout: fixed
In this example, we set three columns to have fixed-widths. The remaining
two columns will be take up the remaining space.
from dash import Dash, dash_table
import pandas as pd
from collections import OrderedDict
data = OrderedDict(
[
("Date", ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"]),
("Region", ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"]),
("Temperature", [1, -20, 3.512, 4, 10423, -441.2]),
("Humidity", [10, 20, 30, 40, 50, 60]),
("Pressure", [2, 10924, 3912, -10, 3591.2, 15]),
]
)
df = pd.DataFrame(data)
app = Dash()
app.layout = dash_table.DataTable(
data=df.to_dict('records'),
columns=[{'id': c, 'name': c} for c in df.columns],
style_cell_conditional=[
{'if': {'column_id': 'Temperature'},
'width': '130px'},
{'if': {'column_id': 'Humidity'},
'width': '130px'},
{'if': {'column_id': 'Pressure'},
'width': '130px'},
]
)
if __name__ == '__main__':
app.run(debug=True)
You can set the width of all of the columns with style_data
and
override a single column with style_cell_conditional
.
from dash import Dash, dash_table
import pandas as pd
from collections import OrderedDict
data = OrderedDict(
[
("Date", ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"]),
("Region", ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"]),
("Temperature", [1, -20, 3.512, 4, 10423, -441.2]),
("Humidity", [10, 20, 30, 40, 50, 60]),
("Pressure", [2, 10924, 3912, -10, 3591.2, 15]),
]
)
df = pd.DataFrame(data)
app = Dash()
app.layout = dash_table.DataTable(
data=df.to_dict('records'),
columns=[{'id': c, 'name': c} for c in df.columns],
style_data={
'width': '100px',
'maxWidth': '100px',
'minWidth': '100px',
},
style_cell_conditional=[
{
'if': {'column_id': 'Region'},
'width': '250px'
},
],
style_table={
'overflowX': 'auto'
}
)
if __name__ == '__main__':
app.run(debug=True)