使用 JavaScript 将 tsv 文件上传按钮添加到 Jupyter Notebook
Add tsv file upload button to Jupyter Notebook using JavaScript
所以我正在使用 Jupyter 4.x 和 python 3.5,试图 "upload" 一个 .tsv
,但实际上只是试图将它捕获为一个字符串然后使用
setTimeout(function(){IPython.notebook.kernel.execute("stringData=StringIO(+"fr.result")");},5000);
让 FileReader()
对象有时间完成二进制字符串转换,然后将字符串保存到 python 变量中。我通过在控制台中打印整个 .tsv
文件来测试 Filereader()
是否正常工作。但是,出于某种原因,python side.Here 中的 stringData 仍未定义 javascript 单元格:
%%HTML
<input type="file" id="CSVFileInput" onchange="handleFiles(this.files)" value="upload csv">
<script>
var inputElement=document.getElementById('CSVFileInput');
function handleFiles() {
var file = inputElement.files[0];
var fr = new FileReader();
fr.readAsText(file);
var outputString=fr.result;
var command = "dataString ='"+outputString+"'";
setTimeout(function(){
IPython.notebook.kernel.execute(command);}
,5000);
}
inputElement.addEventListener("change", handleFiles, false);
</script>
然后在下一个单元格中我测试输出并得到 NameError
因为 dataString
未定义,这是下一个单元格:
dataString
此外,我对 javascript 有点陌生,所以欢迎任何建议,我只是认为这是简单的方法。请问?当然,非常感谢!
FileReader
方法是异步的,因此在您尝试将 outputString
设置为结果时没有加载数据。
处理这个问题的正确方法是使用load
事件处理程序,因此可以将代码修改为以下内容,而不是使用不可靠的异步处理setTimeout()
:
function handleFiles() {
var file = this.files[0]; // "this" is the calling element
var fr = new FileReader();
fr.onload = function() {
var outputString = this.result; // here the data is ready. Now "this" = fr
var command = "dataString ='" + outputString + "'";
IPython.notebook.kernel.execute(command);
};
fr.readAsText(file); // invoked asynchronously
}
同时删除 HTML 中的内联 JavaScript:
<input type="file" id="CSVFileInput" onchange="handleFiles(this.files)" value="upload csv">
到
<input type="file" id="CSVFileInput" title="upload csv">
(value
在输入为type=file
时无效,请改用title
)。然后使用以下代码处理事件(在 DOM 加载后):
document.getElementById("CSVFileInput").addEventListener("change", handleFiles);
function handleFiles() {
var file = this.files[0]; // "this" is the calling element
var fr = new FileReader();
fr.onload = function() {
var outputString = this.result; // here the data is ready. Now "this" = fr
var command = "dataString ='" + outputString + "'";
//IPython.notebook.kernel.execute(command);
console.log("Loaded file. Command:", command);
};
fr.readAsText(file); // invoked asynchronously
}
document.getElementById("CSVFileInput").addEventListener("change", handleFiles);
<input type="file" id="CSVFileInput" title="upload csv">
所以,@K3N 确实给了我一个有价值的难题和异步函数的教训。然而,主要问题是 python 无法识别它从 javascript 接收到的字符串输入,所以我想与大家分享我的旅程。我最终将字符串转换为 2d javascript 数组,然后我 shift()
关闭列名的第一行,转置剩余的行,并清除英语中所有阻止它的愚蠢内容工作(引号和撇号)。现在我可以 pd.DataFrame(dict(zip(colNames,cols)))
和 运行 我 运行 在同一个 .tsv
上的所有计算,当我从我的文件系统读取它时。这是完整的脚本,基本上是 @K3N 向我展示的修复以及 pythonify(arr)
函数:
<input type="file" id="TSVFileInput" title="upload tsv">
function handleFiles() {
//read in file and instantiate filereader
let file = this.files[0];// "this" is the calling element
let fr = new FileReader();
fr.onload = function() {
//split on row delimeter (CRLF)
let outputBuffer = this.result.split("\r\n");
let command;
// split outputBuffer into 2d array
outputBuffer= outputBuffer.map(line => line.split("\t"));
//pop names row from output Buffer
let names=outputBuffer.shift();
//optimized transpose
outputBuffer=outputBuffer.reduce(
(temp,row) =>
row.map((element,i) =>
(temp[i] || []).concat(element))
,[] //initializes temp
);
//build python command
command="colNames ="+pythonify(names);
//send command to notebook kernel
IPython.notebook.kernel.execute(command);
//loop appends columns on python side
for(let i=0 ; i< outputBuffer.length ; i++){
command="cols.append("+pythonify(outputBuffer[i])+")";
IPython.notebook.kernel.execute(command); //send command to kernel
}
}; //end fr.onload()
fr.readAsText(file); // invoked asynchronously, triggers fr.onload
}//end handleFiles()
function pythonify (arr){
//turns javascript array into string representation of python list
let out= '[';
for(let i=0 ; i<arr.length ; i++){
var element=arr[i];
//format double and single quotes
element=element.replace(/\"/g,'\"').replace(/'/g,"\'");
//use python raw string
out+='r"'+element+'"';
if(i<arr.length-1){ //skip last comma
out+=',';
}
}
out+=']';
return out;
}// end pythonify(arr)
document.getElementById("CSVFileInput").addEventListener("change", handleFiles);
所以我正在使用 Jupyter 4.x 和 python 3.5,试图 "upload" 一个 .tsv
,但实际上只是试图将它捕获为一个字符串然后使用
setTimeout(function(){IPython.notebook.kernel.execute("stringData=StringIO(+"fr.result")");},5000);
让 FileReader()
对象有时间完成二进制字符串转换,然后将字符串保存到 python 变量中。我通过在控制台中打印整个 .tsv
文件来测试 Filereader()
是否正常工作。但是,出于某种原因,python side.Here 中的 stringData 仍未定义 javascript 单元格:
%%HTML
<input type="file" id="CSVFileInput" onchange="handleFiles(this.files)" value="upload csv">
<script>
var inputElement=document.getElementById('CSVFileInput');
function handleFiles() {
var file = inputElement.files[0];
var fr = new FileReader();
fr.readAsText(file);
var outputString=fr.result;
var command = "dataString ='"+outputString+"'";
setTimeout(function(){
IPython.notebook.kernel.execute(command);}
,5000);
}
inputElement.addEventListener("change", handleFiles, false);
</script>
然后在下一个单元格中我测试输出并得到 NameError
因为 dataString
未定义,这是下一个单元格:
dataString
此外,我对 javascript 有点陌生,所以欢迎任何建议,我只是认为这是简单的方法。请问?当然,非常感谢!
FileReader
方法是异步的,因此在您尝试将 outputString
设置为结果时没有加载数据。
处理这个问题的正确方法是使用load
事件处理程序,因此可以将代码修改为以下内容,而不是使用不可靠的异步处理setTimeout()
:
function handleFiles() {
var file = this.files[0]; // "this" is the calling element
var fr = new FileReader();
fr.onload = function() {
var outputString = this.result; // here the data is ready. Now "this" = fr
var command = "dataString ='" + outputString + "'";
IPython.notebook.kernel.execute(command);
};
fr.readAsText(file); // invoked asynchronously
}
同时删除 HTML 中的内联 JavaScript:
<input type="file" id="CSVFileInput" onchange="handleFiles(this.files)" value="upload csv">
到
<input type="file" id="CSVFileInput" title="upload csv">
(value
在输入为type=file
时无效,请改用title
)。然后使用以下代码处理事件(在 DOM 加载后):
document.getElementById("CSVFileInput").addEventListener("change", handleFiles);
function handleFiles() {
var file = this.files[0]; // "this" is the calling element
var fr = new FileReader();
fr.onload = function() {
var outputString = this.result; // here the data is ready. Now "this" = fr
var command = "dataString ='" + outputString + "'";
//IPython.notebook.kernel.execute(command);
console.log("Loaded file. Command:", command);
};
fr.readAsText(file); // invoked asynchronously
}
document.getElementById("CSVFileInput").addEventListener("change", handleFiles);
<input type="file" id="CSVFileInput" title="upload csv">
所以,@K3N 确实给了我一个有价值的难题和异步函数的教训。然而,主要问题是 python 无法识别它从 javascript 接收到的字符串输入,所以我想与大家分享我的旅程。我最终将字符串转换为 2d javascript 数组,然后我 shift()
关闭列名的第一行,转置剩余的行,并清除英语中所有阻止它的愚蠢内容工作(引号和撇号)。现在我可以 pd.DataFrame(dict(zip(colNames,cols)))
和 运行 我 运行 在同一个 .tsv
上的所有计算,当我从我的文件系统读取它时。这是完整的脚本,基本上是 @K3N 向我展示的修复以及 pythonify(arr)
函数:
<input type="file" id="TSVFileInput" title="upload tsv">
function handleFiles() {
//read in file and instantiate filereader
let file = this.files[0];// "this" is the calling element
let fr = new FileReader();
fr.onload = function() {
//split on row delimeter (CRLF)
let outputBuffer = this.result.split("\r\n");
let command;
// split outputBuffer into 2d array
outputBuffer= outputBuffer.map(line => line.split("\t"));
//pop names row from output Buffer
let names=outputBuffer.shift();
//optimized transpose
outputBuffer=outputBuffer.reduce(
(temp,row) =>
row.map((element,i) =>
(temp[i] || []).concat(element))
,[] //initializes temp
);
//build python command
command="colNames ="+pythonify(names);
//send command to notebook kernel
IPython.notebook.kernel.execute(command);
//loop appends columns on python side
for(let i=0 ; i< outputBuffer.length ; i++){
command="cols.append("+pythonify(outputBuffer[i])+")";
IPython.notebook.kernel.execute(command); //send command to kernel
}
}; //end fr.onload()
fr.readAsText(file); // invoked asynchronously, triggers fr.onload
}//end handleFiles()
function pythonify (arr){
//turns javascript array into string representation of python list
let out= '[';
for(let i=0 ; i<arr.length ; i++){
var element=arr[i];
//format double and single quotes
element=element.replace(/\"/g,'\"').replace(/'/g,"\'");
//use python raw string
out+='r"'+element+'"';
if(i<arr.length-1){ //skip last comma
out+=',';
}
}
out+=']';
return out;
}// end pythonify(arr)
document.getElementById("CSVFileInput").addEventListener("change", handleFiles);