I’m trying to incorporate this ‘Download Data’ into the dash_table_example. I have it working, however I can’t seem to figure out how to keep the ‘selected_row_indices’ aligned to what is visually shown on the dt.DataTable() element. Ie. I only want to download the selected rows, but can only do so right now based on the index of the original dataframe. I’d like to do it based on the updated dt.DataTable() - after filtering, sorting, etc.
I’m sure it is simple (and I’m a newbie) so just looking for someone to get me unstuck.
Here is my code:
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 json
import pandas as pd
import numpy as np
import plotly
import urllib
import flask
import io
app = dash.Dash()
app.scripts.config.serve_locally = True
# app.css.config.serve_locally = 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_GAPMINDER.loc[0:20]
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']
})
ROWS = [
{'a': 'AA', 'b': 1},
{'a': 'AB', 'b': 2},
{'a': 'BB', 'b': 3},
{'a': 'BC', 'b': 4},
{'a': 'CC', 'b': 5},
{'a': 'CD', 'b': 6}
]
app.layout = html.Div([
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=True,
sortable=True,
selected_row_indices=[],
id='datatable-gapminder'
),
html.Div(id='selected-indexes'),
html.A(
'Download Data',
id='download-link',
download="rawdata.csv",
href="",
target="_blank"
),
dcc.Graph(
id='graph-gapminder'
),
], className="container")
def filter_data(selected_row_indices):
dff = DF_GAPMINDER.iloc[selected_row_indices]
return dff
@app.callback(
dash.dependencies.Output('download-link', 'href'),
[dash.dependencies.Input('datatable-gapminder', 'selected_row_indices')])
def update_download_link(selected_row_indices):
dff = filter_data(selected_row_indices)
csv_string = dff.to_csv(index=False, encoding='utf-8')
csv_string = "data:text/csv;charset=utf-8," + urllib.parse.quote(csv_string)
return csv_string
@app.callback(
Output('datatable-gapminder', 'selected_row_indices'),
[Input('graph-gapminder', 'clickData')],
[State('datatable-gapminder', 'selected_row_indices')])
def update_selected_row_indices(clickData, selected_row_indices):
if clickData:
for point in clickData['points']:
if point['pointNumber'] in selected_row_indices:
selected_row_indices.remove(point['pointNumber'])
else:
selected_row_indices.append(point['pointNumber'])
return selected_row_indices
@app.callback(
Output('graph-gapminder', 'figure'),
[Input('datatable-gapminder', 'rows'),
Input('datatable-gapminder', 'selected_row_indices')])
def update_figure(rows, selected_row_indices):
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_row_indices 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': 40,
'r': 10,
't': 60,
'b': 200
}
fig['layout']['yaxis3']['type'] = 'log'
return fig
app.css.append_css({
"external_url": "https://codepen.io/chriddyp/pen/bWLwgP.css"
})
if __name__ == '__main__':
app.run_server(debug=True)