简体   繁体   English

使用JavaScript将tsv文件上传按钮添加到Jupyter Notebook

[英]Add tsv file upload button to Jupyter Notebook using JavaScript

So I am using Jupyter 4.x and python 3.5, trying to "upload" a .tsv , but really just trying to capture it as a string and then use setTimeout(function(){IPython.notebook.kernel.execute("stringData=StringIO(+"fr.result")");},5000); 所以我正在使用Jupyter 4.x和python 3.5,试图“上传” .tsv ,但实际上只是试图将其捕获为字符串,然后使用setTimeout(function(){IPython.notebook.kernel.execute("stringData=StringIO(+"fr.result")");},5000);

to allow time for the FileReader() object to complete the binary-string conversion then save the string into a python variable. FileReader()对象FileReader()时间来完成二进制字符串转换,然后将字符串保存到python变量中。 I tested that the Filereader() was working by printing the entire .tsv file in the console. 我通过在控制台中打印整个.tsv文件来测试Filereader()是否正常工作。 For some reason, though, stringData remains undefined on the python side.Here is the javascript cell: 由于某种原因,stringData在python端仍然未定义。这是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>

And in the next cell I test the output and get NameError because dataString is undefined, here is the next cell: 在下一个单元格中,我测试输出并得到NameError因为dataString未定义,这是下一个单元格:

dataString

Also, I'm kind of new to javascript, so any and all advice is welcome, I only think this is the easy way. 另外,我是javascript的新手,因此欢迎任何和所有建议,我只认为这是简单的方法。 Pls? 请问 And, of course, thanks a lot! 而且,当然,非常感谢!

FileReader methods are asynchronous so there is no data loaded at the time you try to set outputString to the result. FileReader方法是异步的,因此在您尝试将outputString设置为结果时,没有数据加载。

The proper way to handle this is to use the load event handler, so instead of using setTimeout() , which is unreliable for asynchronous handling, you can modify the code to the following: 解决此问题的正确方法是使用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
}

Also remove the inline JavaScript in the HTML: 还要删除HTML中的内联JavaScript:

<input type="file" id="CSVFileInput" onchange="handleFiles(this.files)" value="upload csv">

to

<input type="file" id="CSVFileInput" title="upload csv">

( value has no effect when input is type=file , use title instead). (当输入为type=filevalue无效,请改为使用title )。 Then use the following code to take care of event handling (after the DOM has loaded): 然后,使用以下代码来处理事件(在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"> 

So, @K3N definitely gave me a valuable piece of the puzzle and lesson in async functions. 因此,@ K3N绝对给了我关于异步功能的难题和教训。 However, the main issue was that python did not recognize the string inputs it was receiving from javascript, so I thought I'd share my journey with all. 但是,主要问题是python无法识别从javascript接收到的字符串输入,因此我想与所有人共享我的旅程。 I ended up converting the string to a 2d javascript array, then I shift() the first row off for the column names, transpose the remaining rows, and clean out all the dumb stuff from english that stops it from working (quotes and apostrophes). 我最终将字符串转换为2d javascript数组,然后将第一行shift()换为列名,转置其余行,然后从英语中清除所有愚蠢的东西,使它停止工作(引号和撇号) 。 Now I can pd.DataFrame(dict(zip(colNames,cols))) and run all the calculations I run on the same .tsv when I read it in from my filesystem. 现在我可以pd.DataFrame(dict(zip(colNames,cols)))和运行所有我在同一个运行计算.tsv ,当我从我的文件系统读取它。 Here is the full script, basically the fixes @K3N showed me plus the pythonify(arr) function: 这是完整的脚本,基本上,@ 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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM