将文件从服务器发送到bokeh上的客户端 [英] send file from server to client on bokeh
问题描述
我已经建立了一个用户界面来从MySQL表中获取数据并对其进行可视化.它在bokeh服务器上运行.我的用户使用他们的浏览器(firefox)远程连接到服务器.效果很好:我只是将表格导入到pandas数据框中.
I have made a user interface to fetch data from a MySQL table and visualize it. It is running on a bokeh server. My users connect remotely to the server using their browser (firefox). This works perfectly fine: I simply import the table into a pandas dataframe.
我的用户还需要以excel格式下载表格.这意味着我不能使用纯JavaScript的 export_csv 示例
My users also need to download the table as excel. This means I cannot use the export_csv example which is pure javascript.
我没有使用JavaScript的经验. 我要做的就是将文件从main.py所在的目录传输到客户端.
I have no experience with JavaScript. All I want is to transfer a file from the directory where my main.py is to the client side.
到目前为止,我尝试过的技术是将普通的on_click
回调连接到按钮,将我需要的信息导出到'output.xls',然后从虚拟字形更改参数,然后再运行Javascript代码.我的想法来自 Bokeh小部件调用CustomJS和Python回调单个事件?.请注意,我尚未将Alpha设置为0,以便在单击下载"按钮后可以看到圆圈是否真的在增大.
The technique I have tried so far is to join a normal on_click
callback to a button, export the information I need to 'output.xls', then change a parameter from a dummy glyph which in turn runs a Javascript code. I got the idea from Bokeh widgets call CustomJS and Python callback for single event? . Note I haven't set the alpha to 0, so that I can see if the circle is really growing upon clicking the download button.
在我的消息的底部,您可以找到我的代码.您可以看到我已经尝试同时使用XMLHttpRequest和Fetch.在前一种情况下,什么也没有发生.在后一种情况下,我会按预期获得名为"mydata.xlsx"的文件,但是该文件仅仅包含以下原始文本:<html><title>404: Not Found</title><body>404: Not Found</body></html>
.
At the bottom of my message you can find my code. You can see I have tried with both XMLHttpRequest and with Fetch directly. In the former case, nothing happens. In the latter case I obtain a file named "mydata.xlsx" as expected, however it contains only this raw text: <html><title>404: Not Found</title><body>404: Not Found</body></html>
.
代码:
p = figure(title='mydata')
#download button
download_b = Button(label="Download", button_type="success")
download_b.on_click(download)
#dummy idea from https://stackoverflow.com/questions/44212250/bokeh-widgets-call-customjs-and-python-callback-for-single-event
dummy = p.circle([1], [1],name='dummy')
JScode_xhr = """
var filename = p.title.text;
filename = filename.concat('.xlsx');
alert(filename);
var xhr = new XMLHttpRequest();
xhr.open('GET', '/output.xlsx', true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
if (this.status == 200) {
var blob = this.response;
alert('seems to work...');
if (navigator.msSaveBlob) {
navigator.msSaveBlob(blob, filename);
}
else {
var link = document.createElement("a");
link = document.createElement('a');
link.href = URL.createObjectURL(blob);
window.open(link.href, '_blank');
link.download = filename;
link.target = "_blank";
link.style.visibility = 'hidden';
link.dispatchEvent(new MouseEvent('click'));
URL.revokeObjectURL(url);
}
}
else {
alert('Ain't working!');
}
};
"""
JScode_fetch = """
var filename = p.title.text;
filename = filename.concat('.xlsx');
alert(filename);
fetch('/output.xlsx').then(response => response.blob())
.then(blob => {
alert(filename);
//addresses IE
if (navigator.msSaveBlob) {
navigator.msSaveBlob(blob, filename);
}
else {
var link = document.createElement("a");
link = document.createElement('a')
link.href = URL.createObjectURL(blob);
window.open(link.href, '_blank');
link.download = filename
link.target = "_blank";
link.style.visibility = 'hidden';
link.dispatchEvent(new MouseEvent('click'))
URL.revokeObjectURL(url);
}
return response.text();
});
"""
dummy.glyph.js_on_change('size', CustomJS(args=dict(p=p),
code=JScode_fetch))
plot_tab = Panel(child=row(download_b,p),
title="Plot",
closable=True,
name=str(self.test))
def download():
writer = pd.ExcelWriter('output.xlsx')
data.to_excel(writer,'data')
infos.to_excel(writer,'info')
dummy = p.select(name='dummy')[0]
dummy.glyph.size = dummy.glyph.size +1
推荐答案
尝试Eugene Pakhomov的答案,我发现了问题所在.
Trying out Eugene Pakhomov's answer, I found what was the issue.
我命名为JScode_fetch
的javascript代码几乎是正确的,但是我得到了404,因为它未正确指向正确的路径.
The javascript code I named JScode_fetch
is almost correct, however I get a 404 because it is not pointing correctly to the right path.
我以目录格式创建了应用程序:我将.py文件更改为main.py
,将其放置在名为app
的文件夹中,并在JScode_fetch
中更改了这一行代码:
I made my application in the directory format: I changed my .py file to main.py
, placed it into a folder called app
, and changed this one line of code in JScode_fetch
:
fetch('/app/static/output.xlsx', {cache: "no-store"}).then(response => response.blob())
[...]
您可以看到问题是它试图访问localhost:5006/output.xlsx
,而不是localhost:5006/app/output.xlsx
.由于采用的是目录格式,因此正确的链接现在为localhost:5006/app/static/output.xlsx
,可以计入static
目录.
You can see the problem was that it was trying to access localhost:5006/output.xlsx
, instead of localhost:5006/app/output.xlsx
. As it is in directory format, the right link is now localhost:5006/app/static/output.xlsx
to count for the static
directory.
我还在download
函数中更改了几行:
I also changed a few lines in the download
function:
def download():
dirpath = os.path.join(os.path.dirname(__file__),'static')
writer = pd.ExcelWriter(os.path.join(dirpath,'output.xlsx'))
writer = pd.ExcelWriter('output.xlsx')
data.to_excel(writer,'data')
infos.to_excel(writer,'info')
dummy = p.select(name='dummy')[0]
dummy.glyph.size = dummy.glyph.size +1
现在它可以正常工作了!
Now it is working flawlessly!
我在fetch()
函数中添加了, {cache: "no-store"}
.否则,如果您必须使用相同的output.xlsx
文件名下载其他数据框excel,则浏览器会认为该文件是相同的.更多信息此处.
edit: I have added , {cache: "no-store"}
within the fetch()
function. Otherwise the browser thinks the file is the same if you have to download a different dataframe excel while using the same output.xlsx
filename. More info here.
这篇关于将文件从服务器发送到bokeh上的客户端的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!