Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JupyterLab extension for perspective rendering #17

Merged
merged 17 commits into from
Feb 2, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions packages/perspective-jupyterlab/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# -*- mode: gitignore; -*-
*~
\#*\#
/.emacs.desktop
/.emacs.desktop.lock
*.elc
auto-save-list
tramp
.\#*

# Org-mode
.org-id-locations
*_archive

# flymake-mode
*_flymake.*

# eshell files
/eshell/history
/eshell/lastdir

# elpa packages
/elpa/

# reftex files
*.rel

# AUCTeX auto folder
/auto/

# cask packages
.cask/
dist/

# Flycheck
flycheck_*.el

# server auth directory
/server/

# projectiles files
.projectile

# directory configuration
.dir-locals.el

# Prerequisites
*.d

# Compiled Object files
*.slo
*.lo
*.o
*.obj

# Precompiled Headers
*.gch
*.pch

# Compiled Dynamic libraries
*.so
*.dylib
*.dll

# Fortran module files
*.mod
*.smod

# Compiled Static libraries
*.lai
*.la
*.a
*.lib

# Executables
*.exe
*.out
*.app

lib
node_modules

.DS_Store
19 changes: 19 additions & 0 deletions packages/perspective-jupyterlab/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Perspective JupyterLab Extension
This extension allows in-lining perspective based charts in jupyterlab notebooks.

## Installation
### From npm
```bash
jupyter labextension install @jpmorganchase/perspective-jupyterlab
```

### From source
From inside the jlab directory:
```bash
npm install
npm run build
jupyter labextension install .
```

### Post install
Copy `node_modules/@jpmorganchase/perspective/build/{asmjs, wasm_async, wasm_sync}` to the jupyterlab build folder (`static` inside of one of the app_dir given from the `jupyter labextension list` command)
38 changes: 38 additions & 0 deletions packages/perspective-jupyterlab/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"name": "@jpmorganchase/perspective-jupyterlab",
"version": "0.1.0",
"description": "psp",
"files": [
"lib/*.d.ts",
"lib/*.js.map",
"lib/*.js",
"lib/*.wasm",
"src/css/*.css"
],
"main": "lib/index.js",
"types": "lib/index.d.ts",
"directories": {
"lib": "lib/"
},
"scripts": {
"start": "tsc",
"clean": "rimraf lib",
"watch": "tsc -w"
},
"dependencies": {
"@jpmorganchase/perspective-viewer": "^0.0.2",
"@jpmorganchase/perspective-viewer-hypergrid": "^0.0.2",
"@jpmorganchase/perspective-viewer-highcharts": "^0.0.2",
"@jupyterlab/application": "^0.15.0",
"@jupyterlab/rendermime-interfaces": "^1.0.0",
"@jupyterlab/services": "^1.1.1-0",
"@phosphor/widgets": "^1.5.0"
},
"devDependencies": {
"rimraf": "~2.6.2",
"typescript": "~2.6.2"
},
"jupyterlab": {
"mimeExtension": true
}
}
13 changes: 13 additions & 0 deletions packages/perspective-jupyterlab/src/css/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/******************************************************************************
*
* Copyright (c) 2017, the Perspective Authors.
*
* This file is part of the Perspective library, distributed under the terms of
* the Apache License 2.0. The full license can be found in the LICENSE file.
*
*/

perspective-viewer.jp-PSPViewer {
display: block;
height:400px;
}
188 changes: 188 additions & 0 deletions packages/perspective-jupyterlab/src/ts/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
/******************************************************************************
*
* Copyright (c) 2017, the Perspective Authors.
*
* This file is part of the Perspective library, distributed under the terms of
* the Apache License 2.0. The full license can be found in the LICENSE file.
*
*/

import {
Widget
} from '@phosphor/widgets';

import {
Message
} from '@phosphor/messaging';

import {
Session
} from '@jupyterlab/services';

import {
IRenderMime
} from '@jupyterlab/rendermime-interfaces';

import '../src/css/index.css';

import "@jpmorganchase/perspective-viewer";
import "@jpmorganchase/perspective-viewer-hypergrid";
import "@jpmorganchase/perspective-viewer-highcharts";

export
const MIME_TYPE = 'application/psp';

export
const PSP_CLASS = 'jp-PSPViewer';

export
const PSP_CONTAINER_CLASS = 'jp-PSPContainer';

export
class RenderedPSP extends Widget implements IRenderMime.IRenderer {
constructor() {
super({ node: Private.createNode() });
}

onAfterAttach(msg: Message) : void{
if (this._loaded) return;
let psp = (<any>(this.node.querySelector('perspective-viewer')));

if(this.datatype === 'static'){
psp.load(this.data);

} else if (this.datatype === 'ws' || this.datatype === 'wss'){
// TODO finish this part eventually
let socket = new WebSocket(this.datasrc);
socket.onopen = function (event: any) {
console.log('connected to ' + this.datasrc);
}.bind(this);
socket.onmessage = function (event: any) {
console.log(event.data);
}.bind(this);

} else if (this.datatype === 'http' || this.datatype === 'https'){
// TODO

} else if (this.datatype === 'comm'){
//grab session id
let els = this.datasrc.replace('comm://', '').split('/');
let kernelId = els[0];
let channel = els[1];

Session.listRunning().then(sessionModels => {
for(let i=0; i<sessionModels.length; i++){
console.log(sessionModels[i]);
if(sessionModels[i].kernel.id === kernelId){
Session.connectTo(sessionModels[i]).then((session) => {

let comm = session.kernel.connectToComm('lantern.live.' + channel);
comm.open('ack');
comm.onMsg = (msg: any) => {
console.log(msg); // 'hello'
let dat = msg['content']['data'];
let tmp = JSON.parse(dat);
psp.update(tmp);
};
comm.onClose = (msg: any) => {
console.log(msg); // 'bye'
};

});
}
}
});
}
}

renderModel(model: IRenderMime.IMimeModel): Promise<void> {
let data = model.data[MIME_TYPE] as string;
console.log(data);
try {
this.data = JSON.parse(data) as object;
this.datatype = 'static';
this.datasrc = '';

if(Object.keys(this.data).length === 0){
this.data = [
{'x': 1, 'y':'a', 'z': true},
{'x': 2, 'y':'b', 'z': false},
{'x': 3, 'y':'c', 'z': true},
{'x': 4, 'y':'d', 'z': false}
];
}


return Promise.resolve();
} catch (e) {
this.datasrc = data;
if(data.indexOf('ws://') !== -1){
this.datatype = 'ws';
} else if(data.indexOf('wss://') !== -1){
this.datatype = 'wss';
} else if(data.indexOf('http://') !== -1){
this.datatype = 'http';
} else if(data.indexOf('https://') !== -1){
this.datatype = 'http';
} else if(data.indexOf('comm://') !== -1){
this.datatype = 'comm';
} else{
throw e;
}
return Promise.resolve();
}
}

data: object;
datatype: string;
datasrc: string;
private _loaded: boolean;
}


export
const rendererFactory: IRenderMime.IRendererFactory = {
safe: false,
mimeTypes: [MIME_TYPE],
createRenderer: options => new RenderedPSP()
};


const extensions: IRenderMime.IExtension | IRenderMime.IExtension[] = [
{
id: 'perspective:factory',
rendererFactory,
dataType: 'string',
fileTypes: [{
name: 'perspective',
fileFormat: 'base64',
mimeTypes: [MIME_TYPE],
extensions: ['psp']
}],
documentWidgetFactoryOptions: {
name: 'perspective',
modelName: 'base64',
primaryFileType: 'psp',
fileTypes: ['psp'],
defaultFor: ['psp']
},
}
];

export default extensions;

namespace Private {
export
let _loaded = false;

export
function createNode(): HTMLElement {
let node = document.createElement('div');
node.className = PSP_CONTAINER_CLASS;
let psp = document.createElement('perspective-viewer');
psp.className = PSP_CLASS;
psp.setAttribute('type', MIME_TYPE);
node.appendChild(psp);
return node;
}
}
15 changes: 15 additions & 0 deletions packages/perspective-jupyterlab/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"compilerOptions": {
"declaration": true,
"noImplicitAny": true,
"noEmitOnError": true,
"noUnusedLocals": true,
"module": "commonjs",
"moduleResolution": "node",
"target": "ES5",
"outDir": "./lib",
"lib": ["ES5", "ES2015.Promise", "DOM", "ES2015.Collection"],
"types": []
},
"include": ["src/ts/*"]
}