# How do I use a TextInput from the user to download in a CSV file the top N rows sorted as per the users sort from a Bokeh DataTable?

**URL:** <https://discourse.bokeh.org/t/how-do-i-use-a-textinput-from-the-user-to-download-in-a-csv-file-the-top-n-rows-sorted-as-per-the-users-sort-from-a-bokeh-datatable/5891>\
**Category:** Community Support\
**Tags:** customjs\
**Created:** [June 30, 2020, 9:15am UTC](https://discourse.bokeh.org/t/how-do-i-use-a-textinput-from-the-user-to-download-in-a-csv-file-the-top-n-rows-sorted-as-per-the-users-sort-from-a-bokeh-datatable/5891 "2020-06-30T09:15:37Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![PSK](https://discourse.bokeh.org/letter_avatar_proxy/v4/letter/p/57b2e6/32.png) [@PSK](https://discourse.bokeh.org/u/PSK)\
**Post date:** [June 30, 2020, 9:15am UTC](https://discourse.bokeh.org/t/how-do-i-use-a-textinput-from-the-user-to-download-in-a-csv-file-the-top-n-rows-sorted-as-per-the-users-sort-from-a-bokeh-datatable/5891/1 "2020-06-30T09:15:38Z")

</div>

I would like to use the TextInput from the user to download the number of specified rows in a CSV file on clicking the download Button. I have used the code from here: [How to Download a DataTable as a .csv in a bokeh\_server app](https://discourse.bokeh.org/t/how-to-download-a-datatable-as-a-csv-in-a-bokeh-server-app/1150)

In the code below the value of the argument “dwnld\_n” doesn’t get updated as per the updated value of the “dwnld\_top.value” instead it remains as the initial value of “dwnld\_top.value” which in this case is 3.

```auto
from bokeh.models.callbacks import CustomJS
import pandas as pd
from bokeh.plotting import ColumnDataSource
from bokeh.models.widgets import Button, DataTable, TableColumn
from bokeh.models import TextInput
from bokeh.layouts import row, column
from bokeh.io import curdoc

js_dwnld = """
var top_n = dwnld_n;
var csv = src.data;
var filetext = 'a,b,c\\n';
for (i=0; i<top_n; i++) {    
    var currRow = [csv['a'][i].toString(),
                   csv['b'][i].toString(),
                   csv['c'][i].toString().concat('\\n')]
    var joined = currRow.join();
    filetext = filetext.concat(joined);    
}
var filename = 'results.csv';
var blob = new Blob([filetext], { type: 'text/csv;charset=utf-8;' });
if (navigator.msSaveBlob) { // IE 10+
    navigator.msSaveBlob(blob, filename);
} 
else {
    var link = document.createElement("a");
    if (link.download !== undefined) { // feature detection
        // Browsers that support HTML5 download attribute
        var url = URL.createObjectURL(blob);
        link.setAttribute("href", url);
        link.setAttribute("download", filename);
        link.style.visibility = 'hidden';
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
    }
}
"""

data = pd.DataFrame({'a':[1,2,3], 'b':[2,3,4], 'c':['d','e','f']})
tab_data = ColumnDataSource(data)
tab_cols = [TableColumn(field="a", title="a"), TableColumn(field="b", title="b"), TableColumn(field="c", title="c")]
tab = DataTable(source=tab_data, columns=tab_cols)

dwnld_top = TextInput(value=str(len(data)), title="Number of rows to download")
dwnld = Button(label='Download')
dwnld.js_on_click(CustomJS(args=dict(src=tab_data, dwnld_n=int(dwnld_top.value)), code=js_dwnld))

layout = row(column(dwnld_top, dwnld), tab)

curdoc().add_root(layout)

```

It would be great if there is a solution to download the data ordered as per the user’s sort applied on the DataTable.

Link to question on stackoverflow: [https://stackoverflow.com/questions/62653275/how-do-i-use-a-textinput-from-the-user-to-download-in-a-csv-file-the-top-n-rows](https://stackoverflow.com/questions/62653275/how-do-i-use-a-textinput-from-the-user-to-download-in-a-csv-file-the-top-n-rows)

I would greatly appreciate any help on this. Thanks!

---

<div class="post-metadata">

**Author:** ![Bryan](https://discourse.bokeh.org/user_avatar/discourse.bokeh.org/bryan/32/3625_2.png) [@Bryan](https://discourse.bokeh.org/u/Bryan)\
**Post date:** [July 1, 2020, 7:24am UTC](https://discourse.bokeh.org/t/how-do-i-use-a-textinput-from-the-user-to-download-in-a-csv-file-the-top-n-rows-sorted-as-per-the-users-sort-from-a-bokeh-datatable/5891/2 "2020-07-01T07:24:20Z")

</div>

@PSK Your problem is here:

```python
dwnld_n=int(dwnld_top.value))

```

The `args` parameter is for mirroring _Bokeh objects_ automagically between Python and JavaScript. You should pass the actual `TextInput` object instead:

```python
dwnld_top=dwnld_top

```

Then in the JS code you can access `dwnld_top.value`

---

<div class="post-metadata">

**Author:** ![PSK](https://discourse.bokeh.org/letter_avatar_proxy/v4/letter/p/57b2e6/32.png) [@PSK](https://discourse.bokeh.org/u/PSK)\
**Post date:** [July 1, 2020, 7:57am UTC](https://discourse.bokeh.org/t/how-do-i-use-a-textinput-from-the-user-to-download-in-a-csv-file-the-top-n-rows-sorted-as-per-the-users-sort-from-a-bokeh-datatable/5891/3 "2020-07-01T07:57:56Z")

</div>

That’s great, thanks a lot @Bryan. I’ll post a link to this page as the answer on stackoverflow.

---

<div class="post-metadata">

**Author:** ![PSK](https://discourse.bokeh.org/letter_avatar_proxy/v4/letter/p/57b2e6/32.png) [@PSK](https://discourse.bokeh.org/u/PSK)\
**Post date:** [July 1, 2020, 10:08am UTC](https://discourse.bokeh.org/t/how-do-i-use-a-textinput-from-the-user-to-download-in-a-csv-file-the-top-n-rows-sorted-as-per-the-users-sort-from-a-bokeh-datatable/5891/4 "2020-07-01T10:08:08Z")

</div>

@Bryan is there a way to preserve the sorting of the DataTable when I download it?

---

<div class="post-metadata">

**Author:** ![Bryan](https://discourse.bokeh.org/user_avatar/discourse.bokeh.org/bryan/32/3625_2.png) [@Bryan](https://discourse.bokeh.org/u/Bryan)\
**Post date:** [July 1, 2020, 3:57pm UTC](https://discourse.bokeh.org/t/how-do-i-use-a-textinput-from-the-user-to-download-in-a-csv-file-the-top-n-rows-sorted-as-per-the-users-sort-from-a-bokeh-datatable/5891/5 "2020-07-01T15:57:03Z")

</div>

@PSK The order of the CSV file is dertermined entirely by the loop in the JS code that appends the lines to the output. It currently just dumps out the data in the order it happens to be in the CDS. You could sort that, but you’d have to do it yourself. i.e. you can sort a list of indices [1…N] according to one of the CDS columns, then use the sorted indices to traverse the CDS in the sorted order when you are dumping the rows.

A “sorted traverse” seems like a reasonable thing to add to BokehJS (and a nice issue for a new contributor). Please feel free to open a [GitHub issue](https://github.com/bokeh/bokeh/issues) to discuss it.

---

<div class="post-metadata">

**Author:** ![PSK](https://discourse.bokeh.org/letter_avatar_proxy/v4/letter/p/57b2e6/32.png) [@PSK](https://discourse.bokeh.org/u/PSK)\
**Post date:** [July 2, 2020, 2:47am UTC](https://discourse.bokeh.org/t/how-do-i-use-a-textinput-from-the-user-to-download-in-a-csv-file-the-top-n-rows-sorted-as-per-the-users-sort-from-a-bokeh-datatable/5891/6 "2020-07-02T02:47:39Z")

</div>

@Bryan From what I understand, this is me sorting the CDS as I would like. But what I would really like is for the CDS to be sorted according to the sort (order) of the DataTable. So for example, if I sorted the DataTable by the column ‘a’ by clicking on the column name (header) in the DataTable and then clicked download I would want that order to be retained in the CSV file. I think what I want is similar to this: [Attribute that captures the ordering of the data in a bokeh DataTable](https://discourse.bokeh.org/t/attribute-that-captures-the-ordering-of-the-data-in-a-bokeh-datatable/3399)

Once I understand that we are on the same page, if you still think it is reasonable to open an issue, I would be more than happy to do that.

Thanks for being so responsive!

---

<div class="post-metadata">

**Author:** ![Bryan](https://discourse.bokeh.org/user_avatar/discourse.bokeh.org/bryan/32/3625_2.png) [@Bryan](https://discourse.bokeh.org/u/Bryan)\
**Post date:** [July 2, 2020, 4:55pm UTC](https://discourse.bokeh.org/t/how-do-i-use-a-textinput-from-the-user-to-download-in-a-csv-file-the-top-n-rows-sorted-as-per-the-users-sort-from-a-bokeh-datatable/5891/7 "2020-07-02T16:55:31Z")

</div>

Unfortunately I don’t know how to obtain the current UI-selected sort column from the `DataTable`. The underlying widget is implemented with the third-party SlickGrid library and I am not sure it exposes that information directly. If you can find information about how to determine the current sort column on SlickGrid I can see how it might be applied (e.g. in a `CustomJS` callback).

---

<div class="post-metadata">

**Author:** ![PSK](https://discourse.bokeh.org/letter_avatar_proxy/v4/letter/p/57b2e6/32.png) [@PSK](https://discourse.bokeh.org/u/PSK)\
**Post date:** [July 2, 2020, 11:32pm UTC](https://discourse.bokeh.org/t/how-do-i-use-a-textinput-from-the-user-to-download-in-a-csv-file-the-top-n-rows-sorted-as-per-the-users-sort-from-a-bokeh-datatable/5891/8 "2020-07-02T23:32:56Z")

</div>

Is this helpful?

> <https://stackoverflow.com/questions/9662967/getting-sort-details-in-slickgrid>

I’m also not sure if it works when you sort by multiple columns.

---

<div class="post-metadata">

**Author:** ![PSK](https://discourse.bokeh.org/letter_avatar_proxy/v4/letter/p/57b2e6/32.png) [@PSK](https://discourse.bokeh.org/u/PSK)\
**Post date:** [July 8, 2020, 7:50am UTC](https://discourse.bokeh.org/t/how-do-i-use-a-textinput-from-the-user-to-download-in-a-csv-file-the-top-n-rows-sorted-as-per-the-users-sort-from-a-bokeh-datatable/5891/9 "2020-07-08T07:50:37Z")

</div>

Hi @Bryan, could you please give me any suggestions on how I could take this forward?

---

<div class="post-metadata">

**Author:** ![Bryan](https://discourse.bokeh.org/user_avatar/discourse.bokeh.org/bryan/32/3625_2.png) [@Bryan](https://discourse.bokeh.org/u/Bryan)\
**Post date:** [July 9, 2020, 12:44am UTC](https://discourse.bokeh.org/t/how-do-i-use-a-textinput-from-the-user-to-download-in-a-csv-file-the-top-n-rows-sorted-as-per-the-users-sort-from-a-bokeh-datatable/5891/10 "2020-07-09T00:44:54Z")

</div>

Im afraid there is not really any great way. To get ahold of the actual `SlickGrid` instance you have to first get ahold of the Bokeh `DataTableView` and that is only available by digging through the global `Bokeh.index`. And if the table is inside any layout, you would need to go through private API as well. As an example, to get to it in the `data_tables.py` example in the repo, it required:

```javascript
Array(...Bokeh.index[1056]._child_views.values())[1].grid.getSortColumns()

```

You will need either to use detailed specific information about the layout that will break if the layout changes at all, or writing some custom generic function that can traverse the graph looking for the data table view that you want. But, if you are willing to do all that, then you could in principle use the result of `getSortColumns` to do the sorting of the CDS.

---

<div class="post-metadata">

**Author:** ![system](https://discourse-uploads.bokeh.org/original/2X/1/14eb24f9e10e4e9b78e3f10f66c04ffa96446e5a.svg) [@system](https://discourse.bokeh.org/u/system)\
**Post date:** [July 21, 2021, 9:26pm UTC](https://discourse.bokeh.org/t/how-do-i-use-a-textinput-from-the-user-to-download-in-a-csv-file-the-top-n-rows-sorted-as-per-the-users-sort-from-a-bokeh-datatable/5891/11 "2021-07-21T21:26:43Z")

</div>


