# How to Download a DataTable as a .csv in a bokeh\_server app

**URL:** <https://discourse.bokeh.org/t/how-to-download-a-datatable-as-a-csv-in-a-bokeh-server-app/1150>\
**Category:** Community Support\
**Created:** [April 18, 2016, 6:33pm UTC](https://discourse.bokeh.org/t/how-to-download-a-datatable-as-a-csv-in-a-bokeh-server-app/1150 "2016-04-18T18:33:25Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![Jordan\_Bramble](https://discourse.bokeh.org/letter_avatar_proxy/v4/letter/j/9dc877/32.png) [@Jordan\_Bramble](https://discourse.bokeh.org/u/Jordan_Bramble)\
**Post date:** [April 18, 2016, 6:33pm UTC](https://discourse.bokeh.org/t/how-to-download-a-datatable-as-a-csv-in-a-bokeh-server-app/1150/1 "2016-04-18T18:33:25Z")

</div>

Hi I have a bokeh server app. running in 0.11.1. One component of my app is a DataTable. I want to save the data in this table as a .csv, so that someone can click a button and download the .csv through their browser. Here is a snipped of what I have done so far.

def download():

export = pd.DataFrame(source6.data)

buffer = io.StringIO()

export.to\_csv(buffer, index=False, encoding=‘utf-8’)

#save(vform(data\_table))

controls = [store\_name, inventory, min\_year, max\_year, min\_month, max\_month, button]

for control in controls[:-1]:

control.on\_change(‘value’, update)

controls[-1].on\_click(download)

the download function, converts the data souce tied to the dataTable to a dataframe. then writes it to the buffer. from their I have no idea how to download it in the browser.

I have a button defined in the app. When this button is clicked the download function is called. but of course that function is not complete. So I am hoping someone can help me download it.

I tried to use the bokeh method save(), but when running on the server, the save function is ignored.

Additionally, I have another issue where everytime I click a button the page is reloaded and a new session is created. This is a bug I believe, that has supposedly been fixed in a PR.

Thanks for the help. Attached are pictures of my app.

![](https://discourse-uploads.bokeh.org/original/1X/cdf10cddf8758b90d58d233f64d9405af038550e.png)

![](https://discourse-uploads.bokeh.org/original/1X/119f8364eebf0ea23d55e15f1a3440bd99dfa3be.png)

---

<div class="post-metadata">

**Author:** ![Jordan\_Bramble](https://discourse.bokeh.org/letter_avatar_proxy/v4/letter/j/9dc877/32.png) [@Jordan\_Bramble](https://discourse.bokeh.org/u/Jordan_Bramble)\
**Post date:** [April 18, 2016, 6:38pm UTC](https://discourse.bokeh.org/t/how-to-download-a-datatable-as-a-csv-in-a-bokeh-server-app/1150/2 "2016-04-18T18:38:11Z")

</div>

Additionally, I wanted to say that I am aware the cherrypy and flask have helper methods for sending files. They will of course not work inside of a bokeh server. I dont quite see how to send a HTTPResponse object. I would also prefer not to rewrite my entire app in Flask or CherryPy in order to embed these dashboards just for the sake of using the send\_file function.

> **···**
>
> On Monday, April 18, 2016 at 2:33:25 PM UTC-4, Jordan Bramble wrote:
> 
> > Hi I have a bokeh server app. running in 0.11.1. One component of my app is a DataTable. I want to save the data in this table as a .csv, so that someone can click a button and download the .csv through their browser. Here is a snipped of what I have done so far.
> 
> > def download():
> 
> > export = pd.DataFrame(source6.data)
> 
> > buffer = io.StringIO()
> 
> > export.to\_csv(buffer, index=False, encoding=‘utf-8’)
> 
> > 
> 
> > #save(vform(data\_table))
> 
> > 
> 
> > controls = [store\_name, inventory, min\_year, max\_year, min\_month, max\_month, button]
> 
> > for control in controls[:-1]:
> 
> > control.on\_change(‘value’, update)
> 
> > controls[-1].on\_click(download)
> 
> > 
> 
> > 
> 
> > the download function, converts the data souce tied to the dataTable to a dataframe. then writes it to the buffer. from their I have no idea how to download it in the browser.
> 
> > I have a button defined in the app. When this button is clicked the download function is called. but of course that function is not complete. So I am hoping someone can help me download it.
> 
> > 
> 
> > I tried to use the bokeh method save(), but when running on the server, the save function is ignored.
> 
> > 
> 
> > Additionally, I have another issue where everytime I click a button the page is reloaded and a new session is created. This is a bug I believe, that has supposedly been fixed in a PR.
> 
> > 
> 
> > Thanks for the help. Attached are pictures of my app.
> 
> > 
> 
> > 
> 
> >

---

<div class="post-metadata">

**Author:** ![Jordan\_Bramble](https://discourse.bokeh.org/letter_avatar_proxy/v4/letter/j/9dc877/32.png) [@Jordan\_Bramble](https://discourse.bokeh.org/u/Jordan_Bramble)\
**Post date:** [April 19, 2016, 7:15pm UTC](https://discourse.bokeh.org/t/how-to-download-a-datatable-as-a-csv-in-a-bokeh-server-app/1150/3 "2016-04-19T19:15:23Z")

</div>

Can anyone offer an example of this?

> **···**
>
> On Monday, April 18, 2016 at 2:33:25 PM UTC-4, Jordan Bramble wrote:
> 
> > Hi I have a bokeh server app. running in 0.11.1. One component of my app is a DataTable. I want to save the data in this table as a .csv, so that someone can click a button and download the .csv through their browser. Here is a snipped of what I have done so far.
> 
> > def download():
> 
> > export = pd.DataFrame(source6.data)
> 
> > buffer = io.StringIO()
> 
> > export.to\_csv(buffer, index=False, encoding=‘utf-8’)
> 
> > 
> 
> > #save(vform(data\_table))
> 
> > 
> 
> > controls = [store\_name, inventory, min\_year, max\_year, min\_month, max\_month, button]
> 
> > for control in controls[:-1]:
> 
> > control.on\_change(‘value’, update)
> 
> > controls[-1].on\_click(download)
> 
> > 
> 
> > 
> 
> > the download function, converts the data souce tied to the dataTable to a dataframe. then writes it to the buffer. from their I have no idea how to download it in the browser.
> 
> > I have a button defined in the app. When this button is clicked the download function is called. but of course that function is not complete. So I am hoping someone can help me download it.
> 
> > 
> 
> > I tried to use the bokeh method save(), but when running on the server, the save function is ignored.
> 
> > 
> 
> > Additionally, I have another issue where everytime I click a button the page is reloaded and a new session is created. This is a bug I believe, that has supposedly been fixed in a PR.
> 
> > 
> 
> > Thanks for the help. Attached are pictures of my app.
> 
> > 
> 
> > 
> 
> >

---

<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:** [April 19, 2016, 8:08pm UTC](https://discourse.bokeh.org/t/how-to-download-a-datatable-as-a-csv-in-a-bokeh-server-app/1150/4 "2016-04-19T20:08:44Z")

</div>

Hi Jordan,

The data table has a data source property, which is a ColumnDataSource. This is turn has a .data property, is just a python dict of named columns. I would imagine it should be straightforward to pass this dict to pandas to get a Dataframe which can then be saved or exported in nay of the ways Pandas supports. Is that the sort of guidance you are looking for?

Bryan

> **···**
>
> > On Apr 19, 2016, at 2:15 PM, Jordan Bramble \<jordanbramble@gmail.com\> wrote:
> > 
> > Can anyone offer an example of this?
> > 
> > On Monday, April 18, 2016 at 2:33:25 PM UTC-4, Jordan Bramble wrote:  
> > Hi I have a bokeh server app. running in 0.11.1. One component of my app is a DataTable. I want to save the data in this table as a .csv, so that someone can click a button and download the .csv through their browser. Here is a snipped of what I have done so far.
> > 
> > def download():  
> > &nbsp;&nbsp;&nbsp;&nbsp;export = pd.DataFrame(source6.data)  
> > &nbsp;&nbsp;&nbsp;&nbsp;buffer = io.StringIO()  
> > &nbsp;&nbsp;&nbsp;&nbsp;export.to\_csv(buffer, index=False, encoding='utf-8')
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;#save(vform(data\_table))
> > 
> > controls = [store\_name, inventory, min\_year, max\_year, min\_month, max\_month, button]  
> > for control in controls[:-1]:  
> > &nbsp;&nbsp;&nbsp;&nbsp;control.on\_change('value', update)  
> > controls[-1].on\_click(download)
> > 
> > the download function, converts the data souce tied to the dataTable to a dataframe. then writes it to the buffer. from their I have no idea how to download it in the browser.  
> > I have a button defined in the app. When this button is clicked the download function is called. but of course that function is not complete. So I am hoping someone can help me download it.
> > 
> > I tried to use the bokeh method save(), but when running on the server, the save function is ignored.
> > 
> > Additionally, I have another issue where everytime I click a button the page is reloaded and a new session is created. This is a bug I believe, that has supposedly been fixed in a PR.
> > 
> > Thanks for the help. Attached are pictures of my app.
> > 
> > --  
> > You received this message because you are subscribed to the Google Groups "Bokeh Discussion - Public" group.  
> > To unsubscribe from this group and stop receiving emails from it, send an email to bokeh+unsubscribe@continuum.io.  
> > To post to this group, send email to bokeh@continuum.io.  
> > To view this discussion on the web visit [https://groups.google.com/a/continuum.io/d/msgid/bokeh/ddc3bee8-afbd-474a-a5c1-5a52cf2a3f18%40continuum.io\](https://groups.google.com/a/continuum.io/d/msgid/bokeh/ddc3bee8-afbd-474a-a5c1-5a52cf2a3f18%40continuum.io%5C).  
> > For more options, visit [https://groups.google.com/a/continuum.io/d/optout\](https://groups.google.com/a/continuum.io/d/optout%5C).

---

<div class="post-metadata">

**Author:** ![Jordan\_Bramble](https://discourse.bokeh.org/letter_avatar_proxy/v4/letter/j/9dc877/32.png) [@Jordan\_Bramble](https://discourse.bokeh.org/u/Jordan_Bramble)\
**Post date:** [April 19, 2016, 8:19pm UTC](https://discourse.bokeh.org/t/how-to-download-a-datatable-as-a-csv-in-a-bokeh-server-app/1150/5 "2016-04-19T20:19:46Z")

</div>

right. That part is quite simple. The difficult part is getting it to download in a web browser, instead of just save to the server at the call of df.to\_csv()

> **···**
>
> On Tue, Apr 19, 2016 at 4:08 PM, Bryan Van de Ven [bryanv@continuum.io](mailto:bryanv@continuum.io) wrote:
> 
> > Hi Jordan,
> > 
> > The data table has a data source property, which is a ColumnDataSource. This is turn has a .data property, is just a python dict of named columns. I would imagine it should be straightforward to pass this dict to pandas to get a Dataframe which can then be saved or exported in nay of the ways Pandas supports. Is that the sort of guidance you are looking for?
> > 
> > Bryan
> > 
> > > On Apr 19, 2016, at 2:15 PM, Jordan Bramble [jordanbramble@gmail.com](mailto:jordanbramble@gmail.com) wrote:
> > 
> > > 
> > 
> > > Can anyone offer an example of this?
> > 
> > > 
> > 
> > > On Monday, April 18, 2016 at 2:33:25 PM UTC-4, Jordan Bramble wrote:
> > 
> > > Hi I have a bokeh server app. running in 0.11.1. One component of my app is a DataTable. I want to save the data in this table as a .csv, so that someone can click a button and download the .csv through their browser. Here is a snipped of what I have done so far.
> > 
> > > 
> > 
> > > def download():
> > 
> > > ```
> > > export = pd.DataFrame(source6.data)
> > > 
> > > ```
> > 
> > > ```
> > > buffer = io.StringIO()
> > > 
> > > ```
> > 
> > > ```
> > > export.to_csv(buffer, index=False, encoding='utf-8')
> > > 
> > > ```
> > 
> > > 
> > 
> > > ```
> > > #save(vform(data_table))
> > > 
> > > ```
> > 
> > > 
> > 
> > > controls = [store\_name, inventory, min\_year, max\_year, min\_month, max\_month, button]
> > 
> > > for control in controls[:-1]:
> > 
> > > ```
> > > control.on_change('value', update)
> > > 
> > > ```
> > 
> > > controls[-1].on\_click(download)
> > 
> > > 
> > 
> > > 
> > 
> > > the download function, converts the data souce tied to the dataTable to a dataframe. then writes it to the buffer. from their I have no idea how to download it in the browser.
> > 
> > > I have a button defined in the app. When this button is clicked the download function is called. but of course that function is not complete. So I am hoping someone can help me download it.
> > 
> > > 
> > 
> > > I tried to use the bokeh method save(), but when running on the server, the save function is ignored.
> > 
> > > 
> > 
> > > Additionally, I have another issue where everytime I click a button the page is reloaded and a new session is created. This is a bug I believe, that has supposedly been fixed in a PR.
> > 
> > > 
> > 
> > > Thanks for the help. Attached are pictures of my app.
> > 
> > > 
> > 
> > > 
> > 
> > > 
> > 
> > > 
> > 
> > > –
> > 
> > > You received this message because you are subscribed to the Google Groups “Bokeh Discussion - Public” group.
> > 
> > > To unsubscribe from this group and stop receiving emails from it, send an email to [bokeh+unsubscribe@continuum.io](mailto:bokeh+unsubscribe@continuum.io).
> > 
> > > To post to this group, send email to [bokeh@continuum.io](mailto:bokeh@continuum.io).
> > 
> > > To view this discussion on the web visit [https://groups.google.com/a/continuum.io/d/msgid/bokeh/ddc3bee8-afbd-474a-a5c1-5a52cf2a3f18%40continuum.io](https://groups.google.com/a/continuum.io/d/msgid/bokeh/ddc3bee8-afbd-474a-a5c1-5a52cf2a3f18%40continuum.io).
> > 
> > > For more options, visit [https://groups.google.com/a/continuum.io/d/optout](https://groups.google.com/a/continuum.io/d/optout).
> > 
> > –
> > 
> > You received this message because you are subscribed to the Google Groups “Bokeh Discussion - Public” group.
> > 
> > To unsubscribe from this group and stop receiving emails from it, send an email to [bokeh+unsubscribe@continuum.io](mailto:bokeh+unsubscribe@continuum.io).
> > 
> > To post to this group, send email to [bokeh@continuum.io](mailto:bokeh@continuum.io).
> 
> > To view this discussion on the web visit [https://groups.google.com/a/continuum.io/d/msgid/bokeh/678EFD14-1A46-460A-AB91-8CC78FE12EB5%40continuum.io](https://groups.google.com/a/continuum.io/d/msgid/bokeh/678EFD14-1A46-460A-AB91-8CC78FE12EB5%40continuum.io).  
> > For more options, visit [https://groups.google.com/a/continuum.io/d/optout](https://groups.google.com/a/continuum.io/d/optout).

---

<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:** [April 19, 2016, 8:34pm UTC](https://discourse.bokeh.org/t/how-to-download-a-datatable-as-a-csv-in-a-bokeh-server-app/1150/6 "2016-04-19T20:34:06Z")

</div>

Jordan,

Ah, I completely misunderstood your question. So, to do this will require some JavaScript. It's possible this could go in a CustomJS callback for a button, maybe? Here are some links that might prove useful:

&nbsp;&nbsp;[pandas - Download CSV from an iPython Notebook - Stack Overflow](http://stackoverflow.com/questions/31893930/download-csv-from-an-ipython-notebook)

&nbsp;&nbsp;[How to export JavaScript array info to csv (on client side)? - Stack Overflow](http://stackoverflow.com/questions/14964035/how-to-export-javascript-array-info-to-csv-on-client-side)

Thanks,

Bryan

> **···**
>
> > On Apr 19, 2016, at 3:19 PM, Jordan Bramble \<jordanbramble@gmail.com\> wrote:
> > 
> > right. That part is quite simple. The difficult part is getting it to download in a web browser, instead of just save to the server at the call of df.to\_csv()
> > 
> > On Tue, Apr 19, 2016 at 4:08 PM, Bryan Van de Ven \<bryan@bokeh.org\> wrote:  
> > Hi Jordan,
> > 
> > The data table has a data source property, which is a ColumnDataSource. This is turn has a .data property, is just a python dict of named columns. I would imagine it should be straightforward to pass this dict to pandas to get a Dataframe which can then be saved or exported in nay of the ways Pandas supports. Is that the sort of guidance you are looking for?
> > 
> > Bryan
> > 
> > \> On Apr 19, 2016, at 2:15 PM, Jordan Bramble \<jordanbramble@gmail.com\> wrote:  
> > \>  
> > \> Can anyone offer an example of this?  
> > \>  
> > \> On Monday, April 18, 2016 at 2:33:25 PM UTC-4, Jordan Bramble wrote:  
> > \> Hi I have a bokeh server app. running in 0.11.1. One component of my app is a DataTable. I want to save the data in this table as a .csv, so that someone can click a button and download the .csv through their browser. Here is a snipped of what I have done so far.  
> > \>  
> > \> def download():  
> > \> export = pd.DataFrame(source6.data)  
> > \> buffer = io.StringIO()  
> > \> export.to\_csv(buffer, index=False, encoding='utf-8')  
> > \>  
> > \> #save(vform(data\_table))  
> > \>  
> > \> controls = [store\_name, inventory, min\_year, max\_year, min\_month, max\_month, button]  
> > \> for control in controls[:-1]:  
> > \> control.on\_change('value', update)  
> > \> controls[-1].on\_click(download)  
> > \>  
> > \>  
> > \> the download function, converts the data souce tied to the dataTable to a dataframe. then writes it to the buffer. from their I have no idea how to download it in the browser.  
> > \> I have a button defined in the app. When this button is clicked the download function is called. but of course that function is not complete. So I am hoping someone can help me download it.  
> > \>  
> > \> I tried to use the bokeh method save(), but when running on the server, the save function is ignored.  
> > \>  
> > \> Additionally, I have another issue where everytime I click a button the page is reloaded and a new session is created. This is a bug I believe, that has supposedly been fixed in a PR.  
> > \>  
> > \> Thanks for the help. Attached are pictures of my app.  
> > \>  
> > \>  
> > \>  
> > \>  
> > \> --  
> > \> You received this message because you are subscribed to the Google Groups "Bokeh Discussion - Public" group.  
> > \> To unsubscribe from this group and stop receiving emails from it, send an email to bokeh+unsubscribe@continuum.io.  
> > \> To post to this group, send email to bokeh@continuum.io.  
> > \> To view this discussion on the web visit [https://groups.google.com/a/continuum.io/d/msgid/bokeh/ddc3bee8-afbd-474a-a5c1-5a52cf2a3f18%40continuum.io\](https://groups.google.com/a/continuum.io/d/msgid/bokeh/ddc3bee8-afbd-474a-a5c1-5a52cf2a3f18%40continuum.io%5C).  
> > \> For more options, visit [https://groups.google.com/a/continuum.io/d/optout\](https://groups.google.com/a/continuum.io/d/optout%5C).
> > 
> > --  
> > You received this message because you are subscribed to the Google Groups "Bokeh Discussion - Public" group.  
> > To unsubscribe from this group and stop receiving emails from it, send an email to bokeh+unsubscribe@continuum.io.  
> > To post to this group, send email to bokeh@continuum.io.  
> > To view this discussion on the web visit [https://groups.google.com/a/continuum.io/d/msgid/bokeh/678EFD14-1A46-460A-AB91-8CC78FE12EB5%40continuum.io\](https://groups.google.com/a/continuum.io/d/msgid/bokeh/678EFD14-1A46-460A-AB91-8CC78FE12EB5%40continuum.io%5C).  
> > For more options, visit [https://groups.google.com/a/continuum.io/d/optout\](https://groups.google.com/a/continuum.io/d/optout%5C).
> > 
> > --  
> > You received this message because you are subscribed to the Google Groups "Bokeh Discussion - Public" group.  
> > To unsubscribe from this group and stop receiving emails from it, send an email to bokeh+unsubscribe@continuum.io.  
> > To post to this group, send email to bokeh@continuum.io.  
> > To view this discussion on the web visit [https://groups.google.com/a/continuum.io/d/msgid/bokeh/CAB%3DGhauh0sJi0zzDgR3b02LjXfj1Q42-ebVw0x29NUTLY%3D1NUg%40mail.gmail.com\](https://groups.google.com/a/continuum.io/d/msgid/bokeh/CAB%3DGhauh0sJi0zzDgR3b02LjXfj1Q42-ebVw0x29NUTLY%3D1NUg%40mail.gmail.com%5C).  
> > For more options, visit [https://groups.google.com/a/continuum.io/d/optout\](https://groups.google.com/a/continuum.io/d/optout%5C).

---

<div class="post-metadata">

**Author:** ![Jordan\_Bramble](https://discourse.bokeh.org/letter_avatar_proxy/v4/letter/j/9dc877/32.png) [@Jordan\_Bramble](https://discourse.bokeh.org/u/Jordan_Bramble)\
**Post date:** [April 19, 2016, 11:29pm UTC](https://discourse.bokeh.org/t/how-to-download-a-datatable-as-a-csv-in-a-bokeh-server-app/1150/7 "2016-04-19T23:29:57Z")

</div>

many thanks to Bryan. Here is an adapted solution I created that will work. Note that button is a Button defined above in the app, and source6 is a ColumnDataSource tied to a data table.

js\_download = “”"

var csv = source.get(‘data’);

var filetext = ‘itemnum,storename,date,usage,netsales\n’;

for (i=0; i \< csv[‘date’].length; i++) {

var currRow = [csv[‘itemnum’][i].toString(),

csv[‘storename’][i].toString(),

csv[‘date’][i].toString(),

csv[‘usage’][i].toString(),

csv[‘netsales’][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);

}

}“”"

button.callback = CustomJS(args=dict(source=source6), code=js\_download)

> **···**
>
> On Tuesday, April 19, 2016 at 4:34:10 PM UTC-4, Bryan Van de ven wrote:
> 
> > Jordan,
> > 
> > Ah, I completely misunderstood your question. So, to do this will require some JavaScript. It’s possible this could go in a CustomJS callback for a button, maybe? Here are some links that might prove useful:
> > 
> > ```
> > [http://stackoverflow.com/questions/31893930/download-csv-from-an-ipython-notebook](http://stackoverflow.com/questions/31893930/download-csv-from-an-ipython-notebook)
> > 
> > [http://stackoverflow.com/questions/14964035/how-to-export-javascript-array-info-to-csv-on-client-side](http://stackoverflow.com/questions/14964035/how-to-export-javascript-array-info-to-csv-on-client-side)
> > 
> > ```
> > 
> > Thanks,
> > 
> > Bryan
> > 
> > > On Apr 19, 2016, at 3:19 PM, Jordan Bramble [jordan...@gmail.com](mailto:jordan...@gmail.com) wrote:
> > 
> > > right. That part is quite simple. The difficult part is getting it to download in a web browser, instead of just save to the server at the call of df.to\_csv()
> > 
> > > On Tue, Apr 19, 2016 at 4:08 PM, Bryan Van de Ven [bry...@continuum.io](mailto:bry...@continuum.io) wrote:
> > 
> > > Hi Jordan,
> > 
> > > The data table has a data source property, which is a ColumnDataSource. This is turn has a .data property, is just a python dict of named columns. I would imagine it should be straightforward to pass this dict to pandas to get a Dataframe which can then be saved or exported in nay of the ways Pandas supports. Is that the sort of guidance you are looking for?
> > 
> > > Bryan
> > 
> > > > On Apr 19, 2016, at 2:15 PM, Jordan Bramble [jordan...@gmail.com](mailto:jordan...@gmail.com) wrote:
> > 
> > > >
> > 
> > > > Can anyone offer an example of this?
> > 
> > > >
> > 
> > > > On Monday, April 18, 2016 at 2:33:25 PM UTC-4, Jordan Bramble wrote:
> > 
> > > > Hi I have a bokeh server app. running in 0.11.1. One component of my app is a DataTable. I want to save the data in this table as a .csv, so that someone can click a button and download the .csv through their browser. Here is a snipped of what I have done so far.
> > 
> > > >
> > 
> > > > def download():
> > 
> > > > ```
> > > > export = pd.DataFrame(source6.data)
> > > > 
> > > > ```
> > 
> > > > ```
> > > > buffer = io.StringIO()
> > > > 
> > > > ```
> > 
> > > > ```
> > > > export.to_csv(buffer, index=False, encoding='utf-8')
> > > > 
> > > > ```
> > 
> > > >
> > 
> > > > ```
> > > > #save(vform(data_table))
> > > > 
> > > > ```
> > 
> > > >
> > 
> > > > controls = [store\_name, inventory, min\_year, max\_year, min\_month, max\_month, button]
> > 
> > > > for control in controls[:-1]:
> > 
> > > > ```
> > > > control.on_change('value', update)
> > > > 
> > > > ```
> > 
> > > > controls[-1].on\_click(download)
> > 
> > > >
> > 
> > > >
> > 
> > > > the download function, converts the data souce tied to the dataTable to a dataframe. then writes it to the buffer. from their I have no idea how to download it in the browser.
> > 
> > > > I have a button defined in the app. When this button is clicked the download function is called. but of course that function is not complete. So I am hoping someone can help me download it.
> > 
> > > >
> > 
> > > > I tried to use the bokeh method save(), but when running on the server, the save function is ignored.
> > 
> > > >
> > 
> > > > Additionally, I have another issue where everytime I click a button the page is reloaded and a new session is created. This is a bug I believe, that has supposedly been fixed in a PR.
> > 
> > > >
> > 
> > > > Thanks for the help. Attached are pictures of my app.
> > 
> > > >
> > 
> > > >
> > 
> > > >
> > 
> > > >
> > 
> > > > –
> > 
> > > > You received this message because you are subscribed to the Google Groups “Bokeh Discussion - Public” group.
> > 
> > > > To unsubscribe from this group and stop receiving emails from it, send an email to [bokeh+un...@continuum.io](mailto:bokeh+un...@continuum.io).
> > 
> > > > To post to this group, send email to [bo...@continuum.io](mailto:bo...@continuum.io).
> > 
> > > > To view this discussion on the web visit [https://groups.google.com/a/continuum.io/d/msgid/bokeh/ddc3bee8-afbd-474a-a5c1-5a52cf2a3f18%40continuum.io](https://groups.google.com/a/continuum.io/d/msgid/bokeh/ddc3bee8-afbd-474a-a5c1-5a52cf2a3f18%40continuum.io).
> > 
> > > > For more options, visit [https://groups.google.com/a/continuum.io/d/optout](https://groups.google.com/a/continuum.io/d/optout).
> > 
> > > –
> > 
> > > You received this message because you are subscribed to the Google Groups “Bokeh Discussion - Public” group.
> > 
> > > To unsubscribe from this group and stop receiving emails from it, send an email to [bokeh+un...@continuum.io](mailto:bokeh+un...@continuum.io).
> > 
> > > To post to this group, send email to [bo...@continuum.io](mailto:bo...@continuum.io).
> > 
> > > To view this discussion on the web visit [https://groups.google.com/a/continuum.io/d/msgid/bokeh/678EFD14-1A46-460A-AB91-8CC78FE12EB5%40continuum.io](https://groups.google.com/a/continuum.io/d/msgid/bokeh/678EFD14-1A46-460A-AB91-8CC78FE12EB5%40continuum.io).
> > 
> > > For more options, visit [https://groups.google.com/a/continuum.io/d/optout](https://groups.google.com/a/continuum.io/d/optout).
> > 
> > > –  
> > > You received this message because you are subscribed to the Google Groups “Bokeh Discussion - Public” group.
> > 
> > > To unsubscribe from this group and stop receiving emails from it, send an email to [bokeh+un...@continuum.io](mailto:bokeh+un...@continuum.io).
> > 
> > > To post to this group, send email to [bo...@continuum.io](mailto:bo...@continuum.io).
> > 
> > > To view this discussion on the web visit [https://groups.google.com/a/continuum.io/d/msgid/bokeh/CAB%3DGhauh0sJi0zzDgR3b02LjXfj1Q42-ebVw0x29NUTLY%3D1NUg%40mail.gmail.com](https://groups.google.com/a/continuum.io/d/msgid/bokeh/CAB%3DGhauh0sJi0zzDgR3b02LjXfj1Q42-ebVw0x29NUTLY%3D1NUg%40mail.gmail.com).
> > 
> > > For more options, visit [https://groups.google.com/a/continuum.io/d/optout](https://groups.google.com/a/continuum.io/d/optout).

---

<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:** [April 20, 2016, 4:44pm UTC](https://discourse.bokeh.org/t/how-to-download-a-datatable-as-a-csv-in-a-bokeh-server-app/1150/8 "2016-04-20T16:44:05Z")

</div>

Jordan,

very cool! Would you be interested in contributing a Pull Request to add a new server example that shows off how to do this?

Thanks,

Bryan

> **···**
>
> > On Apr 19, 2016, at 6:29 PM, Jordan Bramble \<jordanbramble@gmail.com\> wrote:
> > 
> > many thanks to Bryan. Here is an adapted solution I created that will work. Note that button is a Button defined above in the app, and source6 is a ColumnDataSource tied to a data table.
> > 
> > js\_download = """  
> > var csv = source.get('data');  
> > var filetext = 'itemnum,storename,date,usage,netsales\\n';  
> > for (i=0; i \< csv['date'].length; i++) {  
> > &nbsp;&nbsp;&nbsp;&nbsp;var currRow = [csv['itemnum'][i].toString(),  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;csv['storename'][i].toString(),  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;csv['date'][i].toString(),  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;csv['usage'][i].toString(),  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;csv['netsales'][i].toString().concat('\\n')];
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;var joined = currRow.join();  
> > &nbsp;&nbsp;&nbsp;&nbsp;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  
> > &nbsp;&nbsp;&nbsp;&nbsp;// Browsers that support HTML5 download attribute  
> > &nbsp;&nbsp;&nbsp;&nbsp;var url = URL.createObjectURL(blob);  
> > &nbsp;&nbsp;&nbsp;&nbsp;link.setAttribute("href", url);  
> > &nbsp;&nbsp;&nbsp;&nbsp;link.setAttribute("download", filename);  
> > &nbsp;&nbsp;&nbsp;&nbsp;link.style.visibility = 'hidden';  
> > &nbsp;&nbsp;&nbsp;&nbsp;document.body.appendChild(link);  
> > &nbsp;&nbsp;&nbsp;&nbsp;link.click();  
> > &nbsp;&nbsp;&nbsp;&nbsp;document.body.removeChild(link);  
> > }  
> > }"""
> > 
> > button.callback = CustomJS(args=dict(source=source6), code=js\_download)
> > 
> > On Tuesday, April 19, 2016 at 4:34:10 PM UTC-4, Bryan Van de ven wrote:  
> > Jordan,
> > 
> > Ah, I completely misunderstood your question. So, to do this will require some JavaScript. It's possible this could go in a CustomJS callback for a button, maybe? Here are some links that might prove useful:
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[pandas - Download CSV from an iPython Notebook - Stack Overflow](http://stackoverflow.com/questions/31893930/download-csv-from-an-ipython-notebook)
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[How to export JavaScript array info to csv (on client side)? - Stack Overflow](http://stackoverflow.com/questions/14964035/how-to-export-javascript-array-info-to-csv-on-client-side)
> > 
> > Thanks,
> > 
> > Bryan
> > 
> > \> On Apr 19, 2016, at 3:19 PM, Jordan Bramble \<jordan...@gmail.com\> wrote:  
> > \>  
> > \> right. That part is quite simple. The difficult part is getting it to download in a web browser, instead of just save to the server at the call of df.to\_csv()  
> > \>  
> > \> On Tue, Apr 19, 2016 at 4:08 PM, Bryan Van de Ven \<bry...@continuum.io\> wrote:  
> > \> Hi Jordan,  
> > \>  
> > \> The data table has a data source property, which is a ColumnDataSource. This is turn has a .data property, is just a python dict of named columns. I would imagine it should be straightforward to pass this dict to pandas to get a Dataframe which can then be saved or exported in nay of the ways Pandas supports. Is that the sort of guidance you are looking for?  
> > \>  
> > \> Bryan  
> > \>  
> > \> \> On Apr 19, 2016, at 2:15 PM, Jordan Bramble \<jordan...@gmail.com\> wrote:  
> > \> \>  
> > \> \> Can anyone offer an example of this?  
> > \> \>  
> > \> \> On Monday, April 18, 2016 at 2:33:25 PM UTC-4, Jordan Bramble wrote:  
> > \> \> Hi I have a bokeh server app. running in 0.11.1. One component of my app is a DataTable. I want to save the data in this table as a .csv, so that someone can click a button and download the .csv through their browser. Here is a snipped of what I have done so far.  
> > \> \>  
> > \> \> def download():  
> > \> \> export = pd.DataFrame(source6.data)  
> > \> \> buffer = io.StringIO()  
> > \> \> export.to\_csv(buffer, index=False, encoding='utf-8')  
> > \> \>  
> > \> \> #save(vform(data\_table))  
> > \> \>  
> > \> \> controls = [store\_name, inventory, min\_year, max\_year, min\_month, max\_month, button]  
> > \> \> for control in controls[:-1]:  
> > \> \> control.on\_change('value', update)  
> > \> \> controls[-1].on\_click(download)  
> > \> \>  
> > \> \>  
> > \> \> the download function, converts the data souce tied to the dataTable to a dataframe. then writes it to the buffer. from their I have no idea how to download it in the browser.  
> > \> \> I have a button defined in the app. When this button is clicked the download function is called. but of course that function is not complete. So I am hoping someone can help me download it.  
> > \> \>  
> > \> \> I tried to use the bokeh method save(), but when running on the server, the save function is ignored.  
> > \> \>  
> > \> \> Additionally, I have another issue where everytime I click a button the page is reloaded and a new session is created. This is a bug I believe, that has supposedly been fixed in a PR.  
> > \> \>  
> > \> \> Thanks for the help. Attached are pictures of my app.  
> > \> \>  
> > \> \>  
> > \> \>  
> > \> \>  
> > \> \> --  
> > \> \> You received this message because you are subscribed to the Google Groups "Bokeh Discussion - Public" group.  
> > \> \> To unsubscribe from this group and stop receiving emails from it, send an email to bokeh+un...@continuum.io.  
> > \> \> To post to this group, send email to bo...@continuum.io.  
> > \> \> To view this discussion on the web visit [https://groups.google.com/a/continuum.io/d/msgid/bokeh/ddc3bee8-afbd-474a-a5c1-5a52cf2a3f18%40continuum.io\](https://groups.google.com/a/continuum.io/d/msgid/bokeh/ddc3bee8-afbd-474a-a5c1-5a52cf2a3f18%40continuum.io%5C).  
> > \> \> For more options, visit [https://groups.google.com/a/continuum.io/d/optout\](https://groups.google.com/a/continuum.io/d/optout%5C).  
> > \>  
> > \> --  
> > \> You received this message because you are subscribed to the Google Groups "Bokeh Discussion - Public" group.  
> > \> To unsubscribe from this group and stop receiving emails from it, send an email to bokeh+un...@continuum.io.  
> > \> To post to this group, send email to bo...@continuum.io.  
> > \> To view this discussion on the web visit [https://groups.google.com/a/continuum.io/d/msgid/bokeh/678EFD14-1A46-460A-AB91-8CC78FE12EB5%40continuum.io\](https://groups.google.com/a/continuum.io/d/msgid/bokeh/678EFD14-1A46-460A-AB91-8CC78FE12EB5%40continuum.io%5C).  
> > \> For more options, visit [https://groups.google.com/a/continuum.io/d/optout\](https://groups.google.com/a/continuum.io/d/optout%5C).  
> > \>  
> > \>  
> > \> --  
> > \> You received this message because you are subscribed to the Google Groups "Bokeh Discussion - Public" group.  
> > \> To unsubscribe from this group and stop receiving emails from it, send an email to bokeh+un...@continuum.io.  
> > \> To post to this group, send email to bo...@continuum.io.  
> > \> To view this discussion on the web visit [https://groups.google.com/a/continuum.io/d/msgid/bokeh/CAB%3DGhauh0sJi0zzDgR3b02LjXfj1Q42-ebVw0x29NUTLY%3D1NUg%40mail.gmail.com\](https://groups.google.com/a/continuum.io/d/msgid/bokeh/CAB%3DGhauh0sJi0zzDgR3b02LjXfj1Q42-ebVw0x29NUTLY%3D1NUg%40mail.gmail.com%5C).  
> > \> For more options, visit [https://groups.google.com/a/continuum.io/d/optout\](https://groups.google.com/a/continuum.io/d/optout%5C).
> > 
> > --  
> > You received this message because you are subscribed to the Google Groups "Bokeh Discussion - Public" group.  
> > To unsubscribe from this group and stop receiving emails from it, send an email to bokeh+unsubscribe@continuum.io.  
> > To post to this group, send email to bokeh@continuum.io.  
> > To view this discussion on the web visit [https://groups.google.com/a/continuum.io/d/msgid/bokeh/34ca093b-eea7-4d03-b8b4-234e442914f3%40continuum.io\](https://groups.google.com/a/continuum.io/d/msgid/bokeh/34ca093b-eea7-4d03-b8b4-234e442914f3%40continuum.io%5C).  
> > For more options, visit [https://groups.google.com/a/continuum.io/d/optout\](https://groups.google.com/a/continuum.io/d/optout%5C).

---

<div class="post-metadata">

**Author:** ![Jordan\_Bramble](https://discourse.bokeh.org/letter_avatar_proxy/v4/letter/j/9dc877/32.png) [@Jordan\_Bramble](https://discourse.bokeh.org/u/Jordan_Bramble)\
**Post date:** [April 21, 2016, 12:44am UTC](https://discourse.bokeh.org/t/how-to-download-a-datatable-as-a-csv-in-a-bokeh-server-app/1150/9 "2016-04-21T00:44:46Z")

</div>

Totally!

> **···**
>
> On Wed, Apr 20, 2016 at 12:44 PM, Bryan Van de Ven [bryanv@continuum.io](mailto:bryanv@continuum.io) wrote:
> 
> > Jordan,
> > 
> > very cool! Would you be interested in contributing a Pull Request to add a new server example that shows off how to do this?
> > 
> > Thanks,
> > 
> > Bryan
> > 
> > > On Apr 19, 2016, at 6:29 PM, Jordan Bramble [jordanbramble@gmail.com](mailto:jordanbramble@gmail.com) wrote:
> > 
> > > 
> > 
> > > many thanks to Bryan. Here is an adapted solution I created that will work. Note that button is a Button defined above in the app, and source6 is a ColumnDataSource tied to a data table.
> > 
> > > 
> > 
> > > js\_download = “”"
> > 
> > > var csv = source.get(‘data’);
> > 
> > > var filetext = ‘itemnum,storename,date,usage,netsales\n’;
> > 
> > > for (i=0; i \< csv[‘date’].length; i++) {
> > 
> > > ```
> > > var currRow = [csv['itemnum'][i].toString(),
> > > 
> > > ```
> > 
> > > ```
> > > csv['storename'][i].toString(),
> > > 
> > > ```
> > 
> > > ```
> > > csv['date'][i].toString(),
> > > 
> > > ```
> > 
> > > ```
> > > csv['usage'][i].toString(),
> > > 
> > > ```
> > 
> > > ```
> > > csv['netsales'][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);
> > > 
> > > ```
> > 
> > > }
> > 
> > > }“”"
> > 
> > > 
> > 
> > > button.callback = CustomJS(args=dict(source=source6), code=js\_download)
> > 
> > > 
> > 
> > > On Tuesday, April 19, 2016 at 4:34:10 PM UTC-4, Bryan Van de ven wrote:
> > 
> > > Jordan,
> > 
> > > 
> > 
> > > Ah, I completely misunderstood your question. So, to do this will require some JavaScript. It’s possible this could go in a CustomJS callback for a button, maybe? Here are some links that might prove useful:
> > 
> > > 
> > 
> > > ```
> > > [http://stackoverflow.com/questions/31893930/download-csv-from-an-ipython-notebook](http://stackoverflow.com/questions/31893930/download-csv-from-an-ipython-notebook)
> > > 
> > > ```
> > 
> > > 
> > 
> > > ```
> > > [http://stackoverflow.com/questions/14964035/how-to-export-javascript-array-info-to-csv-on-client-side](http://stackoverflow.com/questions/14964035/how-to-export-javascript-array-info-to-csv-on-client-side)
> > > 
> > > ```
> > 
> > > 
> > 
> > > Thanks,
> > 
> > > 
> > 
> > > Bryan
> > 
> > > 
> > 
> > > 
> > 
> > > > On Apr 19, 2016, at 3:19 PM, Jordan Bramble [jordan...@gmail.com](mailto:jordan...@gmail.com) wrote:
> > 
> > > >
> > 
> > > > right. That part is quite simple. The difficult part is getting it to download in a web browser, instead of just save to the server at the call of df.to\_csv()
> > 
> > > >
> > 
> > > > On Tue, Apr 19, 2016 at 4:08 PM, Bryan Van de Ven [bry...@continuum.io](mailto:bry...@continuum.io) wrote:
> > 
> > > > Hi Jordan,
> > 
> > > >
> > 
> > > > The data table has a data source property, which is a ColumnDataSource. This is turn has a .data property, is just a python dict of named columns. I would imagine it should be straightforward to pass this dict to pandas to get a Dataframe which can then be saved or exported in nay of the ways Pandas supports. Is that the sort of guidance you are looking for?
> > 
> > > >
> > 
> > > > Bryan
> > 
> > > >
> > 
> > > > > On Apr 19, 2016, at 2:15 PM, Jordan Bramble [jordan...@gmail.com](mailto:jordan...@gmail.com) wrote:
> > 
> > > > >
> > 
> > > > > Can anyone offer an example of this?
> > 
> > > > >
> > 
> > > > > On Monday, April 18, 2016 at 2:33:25 PM UTC-4, Jordan Bramble wrote:
> > 
> > > > > Hi I have a bokeh server app. running in 0.11.1. One component of my app is a DataTable. I want to save the data in this table as a .csv, so that someone can click a button and download the .csv through their browser. Here is a snipped of what I have done so far.
> > 
> > > > >
> > 
> > > > > def download():
> > 
> > > > > ```
> > > > > export = pd.DataFrame(source6.data)
> > > > > 
> > > > > ```
> > 
> > > > > ```
> > > > > buffer = io.StringIO()
> > > > > 
> > > > > ```
> > 
> > > > > ```
> > > > > export.to_csv(buffer, index=False, encoding='utf-8')
> > > > > 
> > > > > ```
> > 
> > > > >
> > 
> > > > > ```
> > > > > #save(vform(data_table))
> > > > > 
> > > > > ```
> > 
> > > > >
> > 
> > > > > controls = [store\_name, inventory, min\_year, max\_year, min\_month, max\_month, button]
> > 
> > > > > for control in controls[:-1]:
> > 
> > > > > ```
> > > > > control.on_change('value', update)
> > > > > 
> > > > > ```
> > 
> > > > > controls[-1].on\_click(download)
> > 
> > > > >
> > 
> > > > >
> > 
> > > > > the download function, converts the data souce tied to the dataTable to a dataframe. then writes it to the buffer. from their I have no idea how to download it in the browser.
> > 
> > > > > I have a button defined in the app. When this button is clicked the download function is called. but of course that function is not complete. So I am hoping someone can help me download it.
> > 
> > > > >
> > 
> > > > > I tried to use the bokeh method save(), but when running on the server, the save function is ignored.
> > 
> > > > >
> > 
> > > > > Additionally, I have another issue where everytime I click a button the page is reloaded and a new session is created. This is a bug I believe, that has supposedly been fixed in a PR.
> > 
> > > > >
> > 
> > > > > Thanks for the help. Attached are pictures of my app.
> > 
> > > > >
> > 
> > > > >
> > 
> > > > >
> > 
> > > > >
> > 
> > > > > –
> > 
> > > > > You received this message because you are subscribed to the Google Groups “Bokeh Discussion - Public” group.
> > 
> > > > > To unsubscribe from this group and stop receiving emails from it, send an email to [bokeh+un...@continuum.io](mailto:bokeh+un...@continuum.io).
> > 
> > > > > To post to this group, send email to [bo...@continuum.io](mailto:bo...@continuum.io).
> > 
> > > > > To view this discussion on the web visit [https://groups.google.com/a/continuum.io/d/msgid/bokeh/ddc3bee8-afbd-474a-a5c1-5a52cf2a3f18%40continuum.io](https://groups.google.com/a/continuum.io/d/msgid/bokeh/ddc3bee8-afbd-474a-a5c1-5a52cf2a3f18%40continuum.io).
> > 
> > > > > For more options, visit [https://groups.google.com/a/continuum.io/d/optout](https://groups.google.com/a/continuum.io/d/optout).
> > 
> > > >
> > 
> > > > –
> > 
> > > > You received this message because you are subscribed to the Google Groups “Bokeh Discussion - Public” group.
> > 
> > > > To unsubscribe from this group and stop receiving emails from it, send an email to [bokeh+un...@continuum.io](mailto:bokeh+un...@continuum.io).
> > 
> > > > To post to this group, send email to [bo...@continuum.io](mailto:bo...@continuum.io).
> > 
> > > > To view this discussion on the web visit [https://groups.google.com/a/continuum.io/d/msgid/bokeh/678EFD14-1A46-460A-AB91-8CC78FE12EB5%40continuum.io](https://groups.google.com/a/continuum.io/d/msgid/bokeh/678EFD14-1A46-460A-AB91-8CC78FE12EB5%40continuum.io).
> > 
> > > > For more options, visit [https://groups.google.com/a/continuum.io/d/optout](https://groups.google.com/a/continuum.io/d/optout).
> > 
> > > >
> > 
> > > >
> > 
> > > > –
> > 
> > > > You received this message because you are subscribed to the Google Groups “Bokeh Discussion - Public” group.
> > 
> > > > To unsubscribe from this group and stop receiving emails from it, send an email to [bokeh+un...@continuum.io](mailto:bokeh+un...@continuum.io).
> > 
> > > > To post to this group, send email to [bo...@continuum.io](mailto:bo...@continuum.io).
> > 
> > > > To view this discussion on the web visit [https://groups.google.com/a/continuum.io/d/msgid/bokeh/CAB%3DGhauh0sJi0zzDgR3b02LjXfj1Q42-ebVw0x29NUTLY%3D1NUg%40mail.gmail.com](https://groups.google.com/a/continuum.io/d/msgid/bokeh/CAB%3DGhauh0sJi0zzDgR3b02LjXfj1Q42-ebVw0x29NUTLY%3D1NUg%40mail.gmail.com).
> > 
> > > > For more options, visit [https://groups.google.com/a/continuum.io/d/optout](https://groups.google.com/a/continuum.io/d/optout).
> > 
> > > 
> > 
> > > 
> > 
> > > –
> > 
> > > You received this message because you are subscribed to the Google Groups “Bokeh Discussion - Public” group.
> > 
> > > To unsubscribe from this group and stop receiving emails from it, send an email to [bokeh+unsubscribe@continuum.io](mailto:bokeh+unsubscribe@continuum.io).
> > 
> > > To post to this group, send email to [bokeh@continuum.io](mailto:bokeh@continuum.io).
> > 
> > > To view this discussion on the web visit [https://groups.google.com/a/continuum.io/d/msgid/bokeh/34ca093b-eea7-4d03-b8b4-234e442914f3%40continuum.io](https://groups.google.com/a/continuum.io/d/msgid/bokeh/34ca093b-eea7-4d03-b8b4-234e442914f3%40continuum.io).
> > 
> > > For more options, visit [https://groups.google.com/a/continuum.io/d/optout](https://groups.google.com/a/continuum.io/d/optout).
> > 
> > –
> > 
> > You received this message because you are subscribed to the Google Groups “Bokeh Discussion - Public” group.
> > 
> > To unsubscribe from this group and stop receiving emails from it, send an email to [bokeh+unsubscribe@continuum.io](mailto:bokeh+unsubscribe@continuum.io).
> > 
> > To post to this group, send email to [bokeh@continuum.io](mailto:bokeh@continuum.io).
> 
> > To view this discussion on the web visit [https://groups.google.com/a/continuum.io/d/msgid/bokeh/4A430B0D-16D2-41FF-8A83-68628C75A430%40continuum.io](https://groups.google.com/a/continuum.io/d/msgid/bokeh/4A430B0D-16D2-41FF-8A83-68628C75A430%40continuum.io).  
> > For more options, visit [https://groups.google.com/a/continuum.io/d/optout](https://groups.google.com/a/continuum.io/d/optout).

---

<div class="post-metadata">

**Author:** ![Pablo](https://discourse.bokeh.org/letter_avatar_proxy/v4/letter/p/ad7895/32.png) [@Pablo](https://discourse.bokeh.org/u/Pablo)\
**Post date:** [February 16, 2021, 12:17pm UTC](https://discourse.bokeh.org/t/how-to-download-a-datatable-as-a-csv-in-a-bokeh-server-app/1150/10 "2021-02-16T12:17:35Z")

</div>

Thank you so much for providing the example:

> **[bokeh/examples/app/export\_csv at branch-2.3 · bokeh/bokeh](https://github.com/bokeh/bokeh/tree/branch-2.3/examples/app/export_csv)**
>
> branch-2.3/examples/app/export\_csv

It works well. However I’ve realized that Object.keys is returning the columns in alphabetical order, not as they are actually displayed in the table. Is there a way to fix this?

Thanks a lot

---

<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:** [February 16, 2021, 9:46pm UTC](https://discourse.bokeh.org/t/how-to-download-a-datatable-as-a-csv-in-a-bokeh-server-app/1150/11 "2021-02-16T21:46:13Z")

</div>

Probably a couple of ways. Offhand the simplest is probably to pass the Bokeh `DataTable` in to the `CustomJS` callback, then you could iterate over the [`table.columns`](https://docs.bokeh.org/en/latest/docs/reference/models/widgets.tables.html?highlight=datatab%20le#bokeh.models.widgets.tables.DataCube.columns) property to get the `title` (or `field`) off each column in the order the table has them. I don’t have a ready-made example handy, however.

---

<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:08pm UTC](https://discourse.bokeh.org/t/how-to-download-a-datatable-as-a-csv-in-a-bokeh-server-app/1150/12 "2021-07-21T21:08:02Z")

</div>


