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.
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.
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)
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 Part 1. Layout | Dash for Python Documentation | Plotly and Part 2. Basic Callbacks | Dash for Python Documentation | Plotly.
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
Latest version of dash-table-experiments
includes sorting and editing and allows you to listen to those changes through callbacks
:
It’s getting there!
Very cool. Nice one @chriddyp! Can see a load of uses for this. Three requests for the future which I’ll try help with: 1) Ability to remove a column from the table figure 2) Lay a background image for the table 3) export the table as a png
Hi Chris,
This table-viewer is looking really powerful. I’d like to try it out but I get the following console error in my browser when I attempt your example (usage.py). It looks to me like an installation issue, but I’m not a javascript expert: The python package does seem to load in an interpreter. Is there some development environment I need to install, or will the latest dash versions work? (https://plot.ly/dash/installation).
Uncaught (in promise) Error: dash_table_experiments was not found.
at Object.resolve (bundle.js:10)
at i (bundle.js:10)
at Array.map (<anonymous>)
at i (bundle.js:10)
at Array.map (<anonymous>)
at i (bundle.js:10)
at Array.map (<anonymous>)
at i (bundle.js:10)
at Array.map (<anonymous>)
at i (bundle.js:10)
Hi @sagardamle
Typically when using dash component repos you need to run npm i
to install the component before running python usage.py
.
I just cloned the repo and ran into an error when I just ran python usage.py
but the issue was resolved when I ran npm i
and reran python usage.py
.
Let me know if this works for you.
I’m sorry alishobeiri, I must be doing something wrong. I tried a couple of things but both have failed.
- [from the readme from github]: pip install dash-table-experiments
or
- [from the react comopnents installation guide (similar to your instructions above): git clone ‘http://(dash-table-package-url)’ && cd dash-table-experiments && npm install && python usage.py
When I use method #1, the package installs and I can import it in the interpreter, but the package won’t work in a dash app. When I use method #2 I get a couple of warnings during npm installation:
npm WARN optional Skipping failed optional dependency /chokidar/fsevents:
npm WARN notsup Not compatible with your operating system or architecture: fsevents@1.1.2
and then usage.py fails at the load_components.
File "usage.py", line 5, in <module>
import dash_table_experiments as dt
File "/dash-table-experiments/dash_table_experiments/__init__.py", line 10, in <module>
'dash_table_experiments'
File "/usr/software/conda3/4.4.0/lib/python3.6/site-packages/dash/development/component_loader.py", line 22, in load_components
with open(metadata_path) as data_file:
FileNotFoundError: [Errno 2] No such file or directory: '/dash-table-experiments/dash_table_experiments/metadata.json'
I should say I’m happy to wait for Chris’s dash-table to stabilize but at the same time I’ve failed in the past to properly build a component from scratch, so I was thinking this could be a good second example.
Hi @sagardamle
Sorry that’s my bad. I didn’t actually realize Chris had the pip install
command in the README.
In regards to the the second method which I’m personally more familiar with. I’m not sure what those warnings mean, but I think one command I forgot to mention that you should run is: python setup.py install
.
The overall order that should hopefully work is: git clone ‘http://(dash-table-package-url)’ && cd dash-table-experiments && npm install && python setup.py install
&& python usage.py.
I just tried using method #1 and it seemed to get going without an error for me. Maybe trying pip uninstall
and reinstall and see what happens.
Let me know how it goes.
Hi Chris,
-
dash-table-experiments is so cool, if the filter support ‘>, <, >=, <=’ will be better. like https://github.com/bgerm/react-table-sorter-demo
-
When I use the dash-table-experiments, it may disabled the function of Multi-Page Apps and URL Support. I’m not sure if my code is wrong. See below for details:
import dash import dash_core_components as dcc import dash_html_components as html import json import pandas as pd import dash_table_experiments as dt print(dcc.__version__) # 0.6.0 or above is required app = dash.Dash() # Since we're adding callbacks to elements that don't exist in the app.layout, # Dash will raise an exception to warn us that we might be # doing something wrong. # In this case, we're adding the elements through a callback, so we can ignore # the exception. app.scripts.config.serve_locally=True app.config.supress_callback_exceptions = True app.layout = html.Div([ dcc.Location(id='url', refresh=False), html.Div(id='page-content') ]) index_page = html.Div([ dcc.Link('Go to Page 1', href='/page-1'), html.Br(), dcc.Link('Go to Page 2', href='/page-2'), ]) DF_GAPMINDER = pd.read_csv( 'https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv' ) DF_GAPMINDER = DF_GAPMINDER[DF_GAPMINDER['year'] == 2007] page_1_layout = html.Div([ html.H4('Gapminder DataTable'), dt.DataTable( rows=DF_GAPMINDER.to_dict('records'), filterable=True, sortable=True, enable_drag_and_drop = False, id='datatable-gapminder' ), dcc.Graph( id='graph-gapminder' ) ], className="container") @app.callback( dash.dependencies.Output('graph-gapminder', 'figure'), [dash.dependencies.Input('datatable-gapminder', 'rows')]) def update_figure(rows): dff = pd.DataFrame(rows) fig = plotly.tools.make_subplots( rows=3, cols=1, subplot_titles=('Life Expectancy', 'GDP Per Capita', 'Population',), shared_xaxes=True) marker = {'color': '#0074D9'} fig.append_trace({ 'x': dff['country'], 'y': dff['lifeExp'], 'type': 'bar', 'marker': marker }, 1, 1) fig.append_trace({ 'x': dff['country'], 'y': dff['gdpPercap'], 'type': 'bar', 'marker': marker }, 2, 1) fig.append_trace({ 'x': dff['country'], 'y': dff['pop'], 'type': 'bar', 'marker': marker }, 3, 1) fig['layout']['showlegend'] = False fig['layout']['height'] = 800 fig['layout']['margin'] = { 'l': 20, 'r': 20, 't': 60, 'b': 200 } return fig page_2_layout = html.Div([ html.H1('Page 2'), dcc.RadioItems( id='page-2-radios', options=[{'label': i, 'value': i} for i in ['Orange', 'Blue', 'Red']], value='Orange' ), html.Div(id='page-2-content'), html.Br(), dcc.Link('Go to Page 1', href='/page-1'), html.Br(), dcc.Link('Go back to home', href='/') ]) @app.callback(dash.dependencies.Output('page-2-content', 'children'), [dash.dependencies.Input('page-2-radios', 'value')]) def page_2_radios(value): return 'You have selected "{}"'.format(value) # Update the index @app.callback(dash.dependencies.Output('page-content', 'children'), [dash.dependencies.Input('url', 'pathname')]) def display_page(pathname): if pathname == '/page-1': return page_1_layout elif pathname == '/page-2': return page_2_layout else: return index_page # You could also return a 404 "URL not found" page here app.css.append_css({ 'external_url': 'https://codepen.io/chriddyp/pen/bWLwgP.css' }) if __name__ == '__main__': app.run_server(host='0.0.0.0', port=8086, debug=True)
Excellent, dash_table_experiments looks great!
I’m getting Error loading layout when I try it anywhere else aside of Chris’s example, any ideas what can cause this? Thanks!
Hi,
is there also a way to make rows in a table “selectable” and get e.g. the corresponding index in a callback?
Great idea @rumcajs! I just created v0.3.0
which includes row selection. Row selection enables some very sweet crossfiltering applications. Here’s the example from usage.py
(~100 lines of code)
First of all: thank you so mutch for this great table implementation!
I tried to integrate it into an app which uses dcc.Location and dynamic layout.
It seems like if one uses dcc.Location and the URL contains a DataTable the page breaks without any error.
I modified the usage.py
example to demonstrage this behaviour
usage:
- http://127.0.0.1:8050/page1 -> works and shows Headline
- http://127.0.0.1:8050/page2 -> empty page without any error message
import dash
from dash.dependencies import Input, Output, State
import dash_core_components as dcc
import dash_html_components as html
import dash_table_experiments as dt
import pandas as pd
import plotly
app = dash.Dash()
app.config.supress_callback_exceptions = True
DF_WALMART = pd.read_csv(
'https://raw.githubusercontent.com/plotly/datasets/master/1962_2006_walmart_store_openings.csv')
DF_GAPMINDER = pd.read_csv(
'https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv'
)
DF_GAPMINDER = DF_GAPMINDER[DF_GAPMINDER['year'] == 2007]
DF_SIMPLE = pd.DataFrame({
'x': ['A', 'B', 'C', 'D', 'E', 'F'],
'y': [4, 3, 1, 2, 3, 6],
'z': ['a', 'b', 'c', 'a', 'b', 'c']
})
_pages = {
'page1': {
'url': '/page1',
},
'page2': {
'url': '/page2',
}
}
app.layout = html.Div([
html.Div(id="content"),
dcc.Location(id='location', refresh=False)
])
def _get_page_content(name):
if name == 'page1':
return _render_page1()
elif name == 'page2':
return _render_page2()
def _render_page1():
return html.H1('Page 1')
def _render_page2():
return html.Div([
html.H1('Page 2'),
html.H4('Gapminder DataTable'),
dt.DataTable(
rows=DF_GAPMINDER.to_dict('records'),
# optional - sets the order of columns
columns=sorted(DF_GAPMINDER.columns),
row_selectable=True,
filterable=False,
sortable=True,
selected_rows=[],
id='datatable-gapminder'
),
html.Div(id='selected-indexes'),
dcc.Graph(
id='graph-gapminder'
),
html.H4('Simple DataTable'),
dt.DataTable(
rows=DF_SIMPLE.to_dict('records'),
filterable=False,
sortable=True,
id='datatable'
),
dcc.Graph(
id='graph'
),
], className="container")
@app.callback(
Output('datatable-gapminder', 'selected_rows'),
[Input('graph-gapminder', 'clickData')],
[State('datatable-gapminder', 'selected_rows')])
def update_selected_rows(clickData, selected_rows):
if clickData:
new_points = [point['pointNumber'] for point in clickData['points']]
else:
new_points = []
return new_points + selected_rows
@app.callback(
Output('graph-gapminder', 'figure'),
[Input('datatable-gapminder', 'rows'),
Input('datatable-gapminder', 'selected_rows')])
def update_figure(rows, selected_rows):
dff = pd.DataFrame(rows)
fig = plotly.tools.make_subplots(
rows=3, cols=1,
subplot_titles=('Life Expectancy', 'GDP Per Capita', 'Population',),
shared_xaxes=True)
marker = {'color': ['#0074D9'] * len(dff)}
for i in (selected_rows or []):
marker['color'][i] = '#FF851B'
fig.append_trace({
'x': dff['country'],
'y': dff['lifeExp'],
'type': 'bar',
'marker': marker
}, 1, 1)
fig.append_trace({
'x': dff['country'],
'y': dff['gdpPercap'],
'type': 'bar',
'marker': marker
}, 2, 1)
fig.append_trace({
'x': dff['country'],
'y': dff['pop'],
'type': 'bar',
'marker': marker
}, 3, 1)
fig['layout']['showlegend'] = False
fig['layout']['height'] = 800
fig['layout']['margin'] = {
'l': 20,
'r': 20,
't': 60,
'b': 200
}
return fig
@app.callback(
Output('graph', 'figure'),
[Input('datatable', 'rows')])
def update_figure(rows):
dff = pd.DataFrame(rows)
return {
'data': [{
'x': dff['x'],
'y': dff['y'],
'text': dff['z'],
'type': 'bar'
}]
}
@app.callback(
Output('content', 'children'),
[Input('location', 'pathname')])
def display_content(pathname):
if pathname is None:
return html.Div()
matched = [c for c in _pages.keys()
if _pages[c]['url'] == pathname]
if matched and matched[0] != 'index':
content = html.Div([
html.Div(_get_page_content(matched[0])),
])
else:
content = html.H1('Invalid Page')
return content
app.css.append_css({"external_url": "https://codepen.io/chriddyp/pen/bWLwgP.css"})
if __name__ == '__main__':
app.run_server(debug=True)
@HansG Thanks for reporting! I see what’s going on here.
A little context: When Dash serves the page, it crawls the app.layout
to see which component libraries are being used (e.g. dash_core_components
). Then, with this list of unique component libraries, it serves the necessary JS and CSS bundles that are distributed with those component libraries.
In this case, we’re serving dash_table_experiments
on a separate page, as the response of a callback. Dash
only sees dash_html_components
and dash_core_components
in the app.layout
and so it doesn’t serve the necessary JS and CSS bundles that are required for the dash-table-components
component that is rendered in the future.
This is a design flaw of Dash. For now, you can get around this issue by rendering a hidden dash-table-experiments
component in the layout
like:
app.layout = html.Div([
html.Div(id='content'),
dcc.Location(id='location', refresh=False),
html.Div(dt.DataTable(rows=[{}]), style={‘display’: ‘none’})
])
@chriddyp Thanks for the quick fix.
I had to add an empty records dict to the rows property of the DataTables object. Without it dash throws an Error loading dependencies
error in the browser.
But for now, it works!