1

As Jupyter is becoming so popular, I just want to integrate data processing and visualization together using Jupyter. But matplotlib and R ggplot2 are not flexible enough, so I want to use Javascript in Jupyter to draw cool graphs. I have noticed in the newest jupyter, I can write js code with %%javascript in the first line of a cell. But I haven't figured it out that how to exchange data between python and js. For example, in python, I process the data using some algorithms and want to visualize it using D3.js. How can I do that? Thanks for any reply.

user2314737
  • 27,088
  • 20
  • 102
  • 114
Sun Chuanneng
  • 127
  • 1
  • 9

2 Answers2

0

Through the kernel object in the IPython Javascript package. A python statement can be executed from js as follows:

var kernel = IPython.notebook.kernel;
kernel.execute(command);
luminousmen
  • 1,971
  • 1
  • 18
  • 24
  • Thanks for your reply. if I do this, does it mean that I should assign my python code to a javascript string, and kernel.excute this string?@luminousmen – Sun Chuanneng Jan 22 '18 at 15:47
  • @SunChuanneng Not necessary. You can implement functions in python code and just call it in js. – luminousmen Jan 23 '18 at 07:41
0

I've been looking for similar solutions. This helped plus kernal.execute method. I wrote a class to wrap all of this up - interaction between python f-strings and converting into javascript variable

class setvariables { 
constructor(IPython) {
    //super(IPython);
    this.__inprogress = {};
    this.__kernel = IPython.notebook.kernel;
}

// results come back asynchronously.   Check struct that records request is emply 
// before calling requested callback after variables have been set
sync (callback) {
    if (Object.keys(this.__inprogress).length === 0){
        callback();
    } else {
        new Promise(resolve => setTimeout(resolve, 200)).then(() => {this.sync(callback);});
    }
}

// can run anything - doing print("f{var}") and getting results in promise callbacks
execute(cmd) {
    return new Promise((resolve, reject) => {
        var callbacks = {
            iopub: { output: (data) => resolve(data.content.text.trim()) }
        };
        this.__kernel.execute(cmd, callbacks);    
    });
}

// build an f-string to get variable from IPython environment
// format results execute callback function to assign to javascript variable
setjs(name, type, callback) {
    var inprogress = this.__inprogress;
    inprogress[name] = {"type": typeof(type)};
    if (inprogress[name].type==="object" && type instanceof Array) {
        inprogress[name].type="array";
    } else if (inprogress[name].type==="object" && !(type instanceof Array)) {
        inprogress[name].type="dict";
    }
    var cmd = 'print(f"{' + name + '}"';
    // for dict and array replace double quotes to single quotes so JSON.parse works
    if (["dict","array"].includes(inprogress[name].type)) {
        cmd = cmd + '.replace(chr(39),chr(34))';
    }
    cmd = cmd + ')';
    var p = this.execute(cmd);
    p.then((result) => {
        if (["dict","array"].includes(inprogress[name].type)) {
            result = JSON.parse(result);
        } else if (inprogress[name].type === "string") {
            result = result.trim();
        } else {
            result = Number(result);
        }
        /// fetch complete so remove from dict of variables being fetched.
        // Allows sync() to be reliable
        delete inprogress[name];
        callback(result);
    }, (err) => {
        console.warn(err, execute);
    })
 }

}

I intend to put this into a .js file and use require to load it into a %%javascript Jupyter cell. Sample usage below

var td = {};
var data = {};
var array = [];
var num = 0.0;
var str = "";


var py = new setvariables(IPython);
py.setjs("td", td, (result) => { td = result; } );
py.setjs("data", data, (result) => { data = result; } );
py.setjs("array", array, (result) => { array = result; } );
py.setjs("num", num, (result) => { num = result; } );
py.setjs("str", str, (result) => { str = result; } );

// everything is async - all code that depends on values from python needs to be called
// from this block
py.sync(() => {
    console.log(td,"done");
    console.log(data,"done");
    console.log(array,"done");
    console.log(num + 1,"done");
    str = str + " Rob";
    console.log(str,'done');

})
Rob Raymond
  • 29,118
  • 3
  • 14
  • 30