Access data object in Jupyter extension - javascript

I've created a JavaScript extension for my Jupyter Notebook that will plot some data for me. Right now I have the data hardcoded within the extension.
My question: is there a way to access a data object that exists within the Notebook?
For example, below is some sample code for an extension:
define([
'base/js/namespace'
], function(
Jupyter
) {
function test_second_extension() {
var handler = function () {
console.log(
'This is the current notebook application instance:',
Jupyter.notebook
);
var data = [{"x": 1, "y": 5}, {"x": 2, "y":12}, {"x": 3, "y": 27}];
console.log(data);
};
var action = {
icon: 'fa-comment-o', // a font-awesome class used on buttons, etc
help : 'Print notebook instance',
help_index : 'zz',
handler : handler
};
var prefix = 'test_second_extension';
var action_name = 'show-alert';
var full_action_name = Jupyter.actions.register(action, action_name, prefix); // returns 'my_extension:show-alert'
Jupyter.toolbar.add_buttons_group([full_action_name]);
}
return {
load_ipython_extension: test_second_extension
};
});
And this is what I have in a Python3 Jupyter cell:
import pandas as pd
data = pd.read_json('[{"x": 1, "y": 5}, {"x": 2, "y":12}, {"x": 3, "y": 27}]')
Is there a way to access the data object that is created in the Jupyter cell from within the extension, instead of hardcoding it?

A bit janky but try this
from IPython.core.display import Javascript
import json
#list of dicts
list_of_dicts = [{"x": 1, "y": 5}, {"x": 2, "y":12}, {"x": 3, "y": 27}]
#convert to json string
json_list = json.dumps(list_of_dicts)
#run in cell
#This will run in the console check your browser
Javascript("""
var json_list = {};
window.variable = json_list;
console.log(json_list);""".format(json_list))
#or as a function
#replace console_log with what you need
def run_in_console(data):
json_list = json.dumps(data)
return Javascript("""
var json_list = {};
window.variable = json_list;
console.log(json_list);""".format(json_list))

Related

How do I access these JSON values?

I am trying to access JSON values. This is the JSON object:
{
"attrs": {
"width": 1728,
"height": 787,
"dragabble": true
},
"className": "Stage",
"children": [
{
"attrs": {},
"className": "Layer",
"children": [
{
"attrs": {
"stroke": "green",
"strokeWidth": "5",
"points": [
348,564.125
]
},
"className": "Line"
}
]
}
]
}
And I am trying to use these values, like points, here:
socket.on("canvas-data", function(data){
var interval = setInterval(function(){
if(isDrawing) return;
setIsDrawing(true);
clearInterval(interval);
var obj = JSON.parse(data);
setStageData(obj);
var layer = new Konva.Layer();
var lines = new Konva.Line(
{
stroke: stageData.stroke,
strokeWidth: stageData.strokeWidth,
points: stageData.points
})
layer.add(lines);
stageEl.current.add(layer);
}, 200)
})
data is the JSON string, I tried to parse data into obj, set my stageData to obj and then set the corresponding JSON attributes to the values like stroke, strokeWidth and points. This doesn't work however, they're undefined. How do I access them?
(I also tried skipping the step where I set my stageData to obj, and just use obj.stroke instead of stageData.stroke etc.)
You can just skip using setStageData() and use the parsed object directly if you wish, or just name the parsed object stageData by default.
In any case, when you have nested objects and values in an Object, you access them by using the correct index, in your case, it would look this way:
socket.on("canvas-data", function(data) {
var interval = setInterval(function() {
if (isDrawing) return;
setIsDrawing(true);
clearInterval(interval);
var stageData = JSON.parse(data);
var layer = new Konva.Layer();
var lines = new Konva.Line(
{
stroke: stageData.children[0].children[0].attrs.stroke,
strokeWidth: stageData.children[0].children[0].attrs.strokeWidth,
points: stageData.children[0].children[0].attrs.points
});
layer.add(lines);
stageEl.current.add(layer);
}, 200);
})
Doesn't look very nice, but it works. You can always use this app called JSON Path list, which shows you all the possible paths and their values in a JSON object.

getConnectedNodes direction parameter

I have a small issue with the parameter direction of the function getConnectedNodes() based on the Vis.js documentation (search for "getConnectedNodes" in the link)
Any idea to get the direction of the edges using the parameter (i don't know how to)?
JSON Example
[
{ "x": 0, "y": 0, "id": "0", "connections": [ 2 ] // i think here should be a from?},
{ "x": 200, "y": 0, "id": "1", "connections": [ 3, 2 ] },
{ "x": 500, "y": 500, "id": "2", "connections": [ 0, 1 ] },
{ "x": 300, "y": -200, "id": "3", "connections": [ 1 ] }
]
Here part of the code
google.script.run.withSuccessHandler(([nodes, edges]) => new vis.Network(container, {nodes: nodes, edges: edges}, options)).sample();
let network;
function init() {
container = document.getElementById('mynetwork');
exportArea = document.getElementById('input_output');
network = google.script.run.withSuccessHandler(([nodes, edges]) => {network = new vis.Network(container, {nodes: nodes, edges: edges}, options);}).sample();
};
function addConnections(elem, index) {
elem.connections = network.getConnectedNodes(index); < I THINK THE PROBLEM IS HERE
}
function exportNetwork() {
var nodes = objectToArray(network.getPositions());
nodes.forEach(addConnections);
var exportValue = JSON.stringify(nodes, undefined, 2);
exportArea.innerHTML = exportValue;
}
function objectToArray(obj) {
return Object.keys(obj).map(function(key) {
obj[key].id = key;
return obj[key];
});
}
Before hand, thanks a lot!
index is the index of the array like 0, 1, 2,,,. The start index is 0. On the other hand, elem is the object like {x: ###, y: ###, id: ###}. From these situation, I thought that index of getConnectedNodes(index) might be elem.id. So how about the following modification?
From:
elem.connections = network.getConnectedNodes(index);
To:
elem.connections = network.getConnectedNodes(elem.id, "from");
From the document, if you want to retrieve "parent", you can retrieve it by adding from to the argument.
For a node id, returns an array with the id's of the connected nodes.
If optional parameter direction is set to string 'from', only parent nodes are returned.
If direction is set to 'to', only child nodes are returned.
Any other value or undefined returns both parent and child nodes.
When you want to retrieve "child", please add to to the argument instead of from.

Using a variable in an JSON query

I am trying to write a function that can take a field name as an argument and return an array of corresponding values from a bit of JSON.
Example object:
var myObject = [
{"x": 10, "y": 10},
{"x": 20, "y": 10},
{"x": 20, "y": 20},
{"x": 10, "y": 20}
];
My function looks something like this:
function getValues(desiredValue) {
var values = [];
for (i = 0; i < myObject.length; i++) {
values[i] = myObject[i].desiredValue;
}
return values;
}
getValues(x);
Ideally, I would have the argument x passed to the getValues which, instead of looking for a field name called desiredValue would look for a field name called x.
The returned array should look like this:
[10,20,20,10]
As the problem with this code is obvious, how can I get the desired result?
Also, I am trying to avoid unnecessary dependencies, so please don’t give me any JQuery unless absolutely necessary.
You can use map() to return desired result.
var myObject = [
{"x": 10, "y": 10},
{"x": 20, "y": 10},
{"x": 20, "y": 20},
{"x": 10, "y": 20}
];
function getValues(desiredValue) {
return myObject.map(e => e[desiredValue]);
}
console.log(getValues('x'))
You actually need to parse the given JSON string (not the array that you have given here) by using JSON.parse(). See: http://jsbin.com/kevoqe/edit?js,console
a simple utility
//also accepts a path like "foo.bar.baz"
//returns undefined if path can't be resolved
function fetch(path){
var keys = path.split(".");
return function( target ){
for(var t = target, i = 0; i < keys.length; t = t[ keys[ i++ ] ])
if(t == null) return void 0;
return t;
}
}
and it's usage
var myObject = [
{"x": 10, "y": 10},
{"x": 20, "y": 10},
{"x": 20, "y": 20},
{"x": 10, "y": 20}
];
var result = myObject.map( fetch("y") );
this version is a bit more flexible than one hardwired with Array.map() because it can easily be composed with other functions.
Although, especially in this particular case, this already is a little bit of overkill. here you can easily write:
var result = myObject.map(pt => pt.y);
you can't get any shorter and simpler. Or if for some reason the property really is dynamic, you'll have some variable containing it:
var dynamicPropertyName = "y";
//...
var result = myObject.map(pt => pt[ dynamicPropertyName ]);
Use array map method to do manipulation in an array of objects.
Try this code :
var myObject = [
{"x": 10, "y": 10},
{"x": 20, "y": 10},
{"x": 20, "y": 20},
{"x": 10, "y": 20}
];
var output = getValues("x");
console.log(output);
function getValues(desiredValue) {
return myObject.map(function(item) {
return item[desiredValue];
});
}
Output :
Working fiddle : https://jsfiddle.net/ffyjyzjb/

Parsing values from core-response in Polymer

I'm making a request for x and y values from a flax/python backend using Polymer and I can read the values in console for the XMLHttpResquest response, but now I need to convert the output into a set of discrete x and y values (so it can be read by C3.js - a framework sitting on top D3 for graphing).
Here's the code I'm using to get the XMLHttpResquest response:
<paper-button affirmative hover on-tap="{{addNewGraph}}">Submit</paper-button>
Polymer("add-graphItem",{
addNewGraph: function () {
var HeaderName = this.$.graphOptionsLoad.$.headerValue.selectedItem.label;
var FunctionName = this.$.graphFunctionsLoad.$.functionValue.selectedItem.label;
console.log("The options are " +HeaderName +" and " +FunctionName);
var params = {};
if (this.$.graphOptionsLoad.$.headerValue.selectedItem) {
params['DataHeader'] = this.$.graphOptionsLoad.$.headerValue.selectedItem.label;
}
if (this.$.graphFunctionsLoad.$.functionValue.selectedItem) {
params['FunctionName'] = this.$.graphFunctionsLoad.$.functionValue.selectedItem.label;
}
this.$.sendOptions.params = JSON.stringify(params);
var x = this.$.sendOptions.go();
// this.$.sendOptions.go();
console.log(x)
// var ajax = document.querySelector("sendOptions");
var results = [];
this.addEventListener("core-response",
function(e) {
console.log(x.response);
}
);
}
});
And here's an example of the output from console.log(x.response);:
{
"graph": [
{
"Header": "MakeModeChange"
},
{
"x": [
0.0,
131.35,
26971.3,
27044.75,
27351.4,
27404.483333333334,
27419.416666666668,
33128.96666666667,
33549.13333333333,
34049.48333333333,
77464.26666666666,
77609.71666666666,
174171.85,
259166.98333333334
]
},
{
"y": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14
]
}
]
}
Ultimately I need the output to look something like:
['x', 0.0, 131.35, 26971.3, 27044.75, 27351.4, 27404.483333333334...],
['y', 1, 2, 3, 4, 5, 6]
Here's a quick and dirty way to do it - not recommended for large scale or if you don't fully trust the response values. Also, obvious, but if their api/data structures changes you're SOL.
xArr = JSON.parse(x.response).graph[1].x
xArr.unshift('x')
yArr = JSON.parse(y.response).graph[2].y
yArr.unshift('y')
You'll get both arrays you'll need, you can combine as needed

JSON from .NEt WCF to JavaScript array of arrays

I'm using jqPlot and I need to turn this JSON which I receive from a WCF service:
[{ "x": 2, "y": 3 }, { "x": 25, "y": 34 }]
into this array or arrays:
[[2,3],[25,34]]
I've tried JSON.parse & eval but to no avail.
thanks
You can use $.map() to do that:
var data = [{ "x": 2, "y": 3 }, { "x": 25, "y": 34 }]
var flattenedResult = $.map(data, function(point) {
return [[ point.x, point.y ]];
});
Parse the string into an array of objects:
var json = '[{ "x": 2, "y": 3 }, { "x": 25, "y": 34 }]';
var o = $.parseJSON(json);
Then replace each object in the array with an array:
for (var i=0; i<o.length; i++) o[i] = [o[i].x, o[i].y];

Categories