When I sort, the fixed rows get sorted. Is there a property somewhere to govern that behavior?
Hi @jim79lynn ! I think so. You could use a combination of sort_action = 'custom' and a sorting callback, as explained in the documentation:
sort_action( a value equal to: ‘custom’, ‘native’ or ‘none’ ; default'none'): Thesort_actionproperty enables data to be sorted on a per-column basis. If'none', then the sorting UI is not displayed. If'native', then the sorting UI is displayed and the sorting logic is handled by the table. That is, it is performed on the data that exists in thedataproperty. If'custom', the the sorting UI is displayed but it is the responsibility of the developer to program the sorting through a callback (wheresort_bywould be the input anddatawould be the output). Clicking on the sort arrows will update thesort_byproperty.
sort_by( list of dicts ; optional):sort_bydescribes the current state of the sorting UI. That is, if the user clicked on the sort arrow of a column, then this property will be updated with the column ID and the direction (ascordesc) of the sort. For multi-column sorting, this will be a list of sorting parameters, in the order in which they were clicked.
sort_byis a list of dicts with keys:
column_id( string ; required)direction( a value equal to: ‘asc’ or ‘desc’ ; required)
To learn how to write sorting callbacks you can check this doc.
Here you have an example that can be used as a template:
import dash
from dash import Dash, dash_table, dcc, html
from dash.dependencies import Input, Output
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminder2007.csv')
# number of rows that we want to fix
n_fixed = 4
# auxiliar value that will be treated as null in the id column.
# You can change it but you should be careful that it isn't a value that appears in other columns (because it would be trearted as null in those too)
sort_as_null = 'sort_this_row'
# add an id column and set it as the index. Later, we will hide it so that it isn't shown in the app
# At this point the data must be already ordered (the first rows must be the ones that you want to fix)
# we asign a sequential index for the fixed columns and the null (sort_as_null) value for the rest
df['id'] = [str(i) if i <= n_fixed else sort_as_null for i in range(1,len(df)+1)]
app = Dash(__name__)
app.layout = html.Div([
dash_table.DataTable(
id='datatable-interactivity',
columns=[
{"name": i, "id": i, "deletable": True, "selectable": True} for i in df.columns
],
data=df.to_dict('records'),
editable=True,
# here we specify the number of rows to be fixed (n_fixed) and/or the headers. Default { headers: False, data: 0}
fixed_rows = { 'headers': True, 'data': n_fixed},
# here we have the important arguments (sort_action and sort_mode) which must be set to 'custom' and 'multi'
sort_action="custom",
sort_mode="multi",
sort_as_null = [sort_as_null],
# hide id column
hidden_columns = ['id']
)
])
@app.callback(
Output('datatable-interactivity', 'data'),
Input('datatable-interactivity', 'sort_by')
)
def sorting(sort):
if sort is None :
raise dash.exceptions.PreventUpdate
else :
# what we do here is put the id column at the beginning of the sort_by argument
# the result is that our data gets ordered FIRST by the id and then by the other columns that the user specifies
default_order = [{'column_id':'id', 'direction':'asc'}]
if type(sort) == dict : sort = [sort]
sort = default_order + sort
dff = df.sort_values(
by = [s['column_id'] for s in sort],
ascending=[s['direction'] for s in sort],
inplace=False
)
return dff.to_dict('records')
if __name__ == '__main__':
app.run_server(debug=True, use_reloader = False)
Hope this helps! ![]()