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_action
property 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 thedata
property. If'custom'
, the the sorting UI is displayed but it is the responsibility of the developer to program the sorting through a callback (wheresort_by
would be the input anddata
would be the output). Clicking on the sort arrows will update thesort_by
property.
sort_by
( list of dicts ; optional):sort_by
describes 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 (asc
ordesc
) of the sort. For multi-column sorting, this will be a list of sorting parameters, in the order in which they were clicked.
sort_by
is 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!