├── MANIFEST.in
├── nbextension
├── src
│ ├── index.css
│ ├── embed.js
│ ├── index.js
│ ├── extension.js
│ └── renderer.js
├── README.md
├── package.json
└── webpack.config.js
├── component
├── index.js
├── README.md
├── package.json
├── index.css
├── vanilla-table.js
├── fixed-data-table.js
├── virtualized-grid.js
└── virtualized-table.js
├── .gitignore
├── .cookiecutter.yaml
├── jupyterlab_table
├── README.md
└── __init__.py
├── uninstall.sh
├── labextension
├── README.md
├── src
│ ├── index.css
│ ├── output.js
│ ├── plugin.js
│ └── doc.js
├── package.json
└── build_extension.js
├── RELEASE.md
├── setup.py
├── install.sh
├── README.md
└── setupbase.py
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | graft jupyterlab_table/static
2 | graft labextension/src
3 | graft nbextension/src
4 | include labextension/package.json
5 | include nbextension/package.json
6 |
--------------------------------------------------------------------------------
/nbextension/src/index.css:
--------------------------------------------------------------------------------
1 | div.output_subarea.output_JSONTable {
2 | max-width: 100%;
3 | padding: 0;
4 | padding-top: 0.4em;
5 | font-size: 14px;
6 | overflow: hidden;
7 | }
8 |
--------------------------------------------------------------------------------
/component/index.js:
--------------------------------------------------------------------------------
1 | export VirtualizedTable from './virtualized-table';
2 | export VirtualizedGrid from './virtualized-grid';
3 | export FixedDataTable from './fixed-data-table';
4 | export VanillaTable from './vanilla-table';
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | labextension/lib/
2 | nbextension/lib/
3 | nbextension/embed/
4 | node_modules/
5 | npm-debug.log
6 | *.egg-info/
7 | __pycache__/
8 | build/
9 | dist/
10 |
11 | # Compiled javascript
12 | jupyterlab_table/static/
13 |
14 | # OS X
15 | .DS_Store
16 |
--------------------------------------------------------------------------------
/.cookiecutter.yaml:
--------------------------------------------------------------------------------
1 | default_context:
2 | author_name: "Grant Nestor"
3 | author_email: "grantnestor@gmail.com"
4 | mime_type: "application/vnd.dataresource+json"
5 | file_extension: "table.json"
6 | mime_short_name: "JSONTable"
7 | extension_name: "jupyterlab_table"
8 |
--------------------------------------------------------------------------------
/component/README.md:
--------------------------------------------------------------------------------
1 | # component
2 |
3 | A React component for rendering JSONTable
4 |
5 | ## Structure
6 |
7 | * `index.js`: Entry point for React component(s)
8 | * `index.css`: Optional CSS file for styling React component(s)
9 | * `package.json`: Node package configuration, use this to add npm depedencies
10 |
--------------------------------------------------------------------------------
/nbextension/src/embed.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Entry point for the unpkg bundle containing custom model definitions.
3 | *
4 | * It differs from the notebook bundle in that it does not need to define a
5 | * dynamic baseURL for the static assets and may load some css that would
6 | * already be loaded by the notebook otherwise.
7 | */
8 |
9 | export { version } from '../package.json';
10 |
--------------------------------------------------------------------------------
/jupyterlab_table/README.md:
--------------------------------------------------------------------------------
1 | # jupyterlab_table
2 |
3 | Single Python package for lab and notebook extensions
4 |
5 | ## Structure
6 |
7 | * `static`: Built Javascript from `../labextension/` and `../nbextension/`
8 | * `__init__.py`: Exports paths and metadata of lab and notebook extensions and exports an optional `display` method that can be imported into a notebook and used to easily display data using this renderer
9 |
--------------------------------------------------------------------------------
/component/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jupyterlab_table_react",
3 | "version": "1.0.0",
4 | "description": "A React component for rendering JSON schema table",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [
10 | "jupyter",
11 | "react"
12 | ],
13 | "author": "Grant Nestor",
14 | "license": "ISC",
15 | "dependencies": {
16 | "fixed-data-table": "^0.6.3",
17 | "jsontableschema": "^0.2.2",
18 | "react": "^15.3.2",
19 | "react-addons-shallow-compare": "^15.4.2",
20 | "react-virtualized": "^8.11.4"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/uninstall.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | nbExtFlags=$1
3 |
4 | jupyter lab --version
5 | if [ $? -eq 0 ]; then
6 | jupyter labextension uninstall --py $nbExtFlags jupyterlab_test
7 | fi
8 |
9 | jupyter notebook --version
10 | if [ $? -eq 0 ]; then
11 | jupyter nbextension uninstall --py $nbExtFlags jupyterlab_test
12 | fi
13 |
14 | pip --version
15 | if [ $? -eq 0 ]; then
16 | pip uninstall -v .
17 | else
18 | echo "'pip --version' failed, therefore pip is not installed. In order to perform
19 | an install of jupyterlab_table you must have both pip and npm installed on
20 | your machine! See https://packaging.python.org/installing/ for installation instructions."
21 | fi
22 |
--------------------------------------------------------------------------------
/labextension/README.md:
--------------------------------------------------------------------------------
1 | # labextension
2 |
3 | A JupyterLab extension for rendering JSON Table Schema
4 |
5 | ## Prerequisites
6 |
7 | * `jupyterlab@^0.18.0`
8 |
9 | ## Development
10 |
11 | Install dependencies and build Javascript:
12 |
13 | ```bash
14 | npm install
15 | ```
16 |
17 | Re-build Javascript:
18 |
19 | ```bash
20 | npm run build
21 | ```
22 |
23 | Watch `/src` directory and re-build on changes:
24 |
25 | ```bash
26 | npm run watch
27 | ```
28 |
29 | Manage extension
30 |
31 | ```bash
32 | # Install
33 | npm run extension:install
34 | # Enable
35 | npm run extension:enable
36 | # Disable
37 | npm run extension:disable
38 | # Uninstall
39 | npm run extension:uninstall
40 | ```
41 |
--------------------------------------------------------------------------------
/nbextension/src/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Entry point for the notebook bundle containing custom model definitions.
3 | * Setup notebook base URL
4 | * Some static assets may be required by the custom widget javascript. The base
5 | * url for the notebook is not known at build time and is therefore computed
6 | * dynamically.
7 | */
8 |
9 | __webpack_public_path__ = document
10 | .querySelector('body')
11 | .getAttribute('data-base-url') +
12 | 'nbextensions/jupyterlab_table/';
13 |
14 | /**
15 | * Export widget models and views, and the npm package version number.
16 | */
17 | export { register_renderer, render_cells } from './renderer.js';
18 | export { version } from '../package.json';
19 |
--------------------------------------------------------------------------------
/nbextension/README.md:
--------------------------------------------------------------------------------
1 | # nbextension
2 |
3 | A Jupyter Notebook extension for rendering JSON Table Schema
4 |
5 | ## Prerequisites
6 |
7 | * `notebook@>=4.3.0`
8 |
9 | ## Development
10 |
11 | Install dependencies and build Javascript:
12 |
13 | ```bash
14 | npm install
15 | ```
16 |
17 | Re-build Javascript:
18 |
19 | ```bash
20 | npm run build
21 | ```
22 |
23 | Watch `/src` directory and re-build on changes:
24 |
25 | ```bash
26 | npm run watch
27 | ```
28 |
29 | Manage extension
30 |
31 | ```bash
32 | # Install
33 | npm run extension:install
34 | # Enable
35 | npm run extension:enable
36 | # Disable
37 | npm run extension:disable
38 | # Uninstall
39 | npm run extension:uninstall
40 | ```
41 |
--------------------------------------------------------------------------------
/labextension/src/index.css:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) Jupyter Development Team.
3 | Distributed under the terms of the Modified BSD License.
4 | */
5 |
6 | .jp-OutputWidgetJSONTable, .jp-DocWidgetJSONTable {
7 | width: 100%;
8 | padding: 0;
9 | font-size: 13px;
10 | }
11 |
12 | .jp-OutputWidgetJSONTable {
13 | padding-top: 5px;
14 | height: 360px;
15 | }
16 |
17 | .jp-DocWidgetJSONTable {
18 | overflow: hidden;
19 | }
20 |
21 | .jp-DocWidgetJSONTable .jp-mod-error {
22 | width: 100%;
23 | min-height: 100%;
24 | text-align: center;
25 | padding: 10px;
26 | box-sizing: border-box;
27 | }
28 |
29 | .jp-DocWidgetJSONTable .jp-mod-error h2 {
30 | font-size: 18px;
31 | font-weight: 500;
32 | padding-bottom: 10px;
33 | }
34 |
35 | .jp-DocWidgetJSONTable .jp-mod-error pre {
36 | text-align: left;
37 | padding: 10px;
38 | overflow: hidden;
39 | }
40 |
--------------------------------------------------------------------------------
/nbextension/src/extension.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This file contains the javascript that is run when the notebook is loaded.
3 | * It contains some requirejs configuration and the `load_ipython_extension`
4 | * which is required for any notebook extension.
5 | */
6 |
7 | /**
8 | * Configure requirejs.
9 | */
10 | if (window.require) {
11 | window.require.config({
12 | map: {
13 | '*': {
14 | 'jupyterlab_table': 'nbextensions/jupyterlab_table/index'
15 | }
16 | }
17 | });
18 | }
19 |
20 | /**
21 | * Export the required load_ipython_extention.
22 | */
23 | export function load_ipython_extension() {
24 | define(
25 | [
26 | 'nbextensions/jupyterlab_table/index',
27 | 'base/js/namespace',
28 | 'base/js/events',
29 | 'notebook/js/outputarea'
30 | ],
31 | (Extension, Jupyter, events, outputarea) => {
32 | const { notebook } = Jupyter;
33 | const { OutputArea } = outputarea;
34 | Extension.register_renderer(notebook, events, OutputArea);
35 | Extension.render_cells(notebook);
36 | }
37 | );
38 | }
39 |
--------------------------------------------------------------------------------
/component/index.css:
--------------------------------------------------------------------------------
1 | .fixedDataTableLayout_main {
2 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
3 | font-size: 14px;
4 | }
5 |
6 | .public_fixedDataTableCell_main {
7 | border-color: #ddd;
8 | }
9 |
10 | .public_fixedDataTable_header {
11 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
12 | font-size: 14px;
13 | }
14 |
15 | .public_fixedDataTable_header {
16 | background: #fff;
17 | }
18 |
19 | .public_fixedDataTable_header, .public_fixedDataTable_header .public_fixedDataTableCell_main {
20 | background: #fff;
21 | text-align: center;
22 | }
23 |
24 | .public_fixedDataTableCell_cellContent {
25 | padding: 6px 13px;
26 | }
27 |
28 | .public_fixedDataTableRow_highlighted, .public_fixedDataTableRow_highlighted .public_fixedDataTableCell_main {
29 | background: #f8f8f8;
30 | }
31 |
32 | .dataframe {
33 | width: 100%;
34 | border-spacing: 1px;
35 | }
36 |
37 | .dataframe .header {
38 | text-align: right;
39 | }
40 |
--------------------------------------------------------------------------------
/RELEASE.md:
--------------------------------------------------------------------------------
1 | # Making a jupyterlab_table release
2 |
3 | This document guides an extension maintainer through creating and publishing a release of jupyterlab_table. This process creates a Python source package and a Python universal wheel and uploads them to PyPI.
4 |
5 | ## Update version number
6 |
7 | Update the version number in `setup.py`, `labextension/package.json`, and `nbextension/package.json`.
8 |
9 | Commit your changes, add git tag for this version, and push both commit and tag to your origin/remote repo.
10 |
11 | ## Remove generated files
12 |
13 | Remove old Javascript bundle and Python package builds:
14 |
15 | ```bash
16 | git clean -xfd
17 | ```
18 |
19 | ## Build the package
20 |
21 | Build the Javascript extension bundle, then build the Python package and wheel:
22 |
23 | ```bash
24 | bash build.js
25 | python setup.py sdist
26 | python setup.py bdist_wheel --universal
27 | ```
28 |
29 | ## Upload the package
30 |
31 | Upload the Python package and wheel with [twine](https://github.com/pypa/twine). See the Python documentation on [package uploading](https://packaging.python.org/distributing/#uploading-your-project-to-pypi)
32 | for [twine](https://github.com/pypa/twine) setup instructions and for why twine is the recommended uploading method.
33 |
34 | ```bash
35 | twine upload dist/*
36 | ```
37 |
--------------------------------------------------------------------------------
/component/vanilla-table.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | // hack: `stream.Transform` (stream-browserify) is undefined in `csv-parse` when
4 | // built with @jupyterlabextension-builder
5 | import infer from 'jsontableschema/lib/infer';
6 | // import { infer } from 'jsontableschema';
7 | import './index.css';
8 |
9 | function inferSchema(data) {
10 | const headers = data.reduce((result, row) => [...new Set([...result, ...Object.keys(row)])], []);
11 | const values = data.map(row => Object.values(row));
12 | return infer(headers, values);
13 | }
14 |
15 | export default class VanillaTable extends React.Component {
16 |
17 | render() {
18 | let { schema, data } = this.props;
19 | if (!schema) schema = inferSchema(data);
20 | return (
21 |
22 |
23 |
24 | {
25 | schema.fields.map((field, index) => (
26 | | {field.name} |
27 | ))
28 | }
29 |
30 |
31 |
32 | {
33 | props.data.map((row, rowIndex) =>
34 |
35 | {
36 | schema.fields.map((field, index) => (
37 | | {row[field.name]} |
38 | ))
39 | }
40 |
41 | )
42 | }
43 |
44 |
45 | );
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/nbextension/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "name": "jupyterlab_table_nbextension",
4 | "version": "0.18.0",
5 | "description": "A Jupyter Notebook extension for rendering JSON Table Schema",
6 | "author": "Grant Nestor ",
7 | "main": "src/index.js",
8 | "keywords": [
9 | "jupyter",
10 | "jupyterlab",
11 | "jupyterlab extension"
12 | ],
13 | "scripts": {
14 | "build": "webpack",
15 | "watch": "watch \"npm install\" src ../component --wait 10 --ignoreDotFiles",
16 | "preinstall": "npm install ../component",
17 | "prepublish": "npm run build",
18 | "extension:install": "jupyter nbextension install --symlink --py --sys-prefix jupyterlab_table",
19 | "extension:uninstall": "jupyter nbextension uninstall --py --sys-prefix jupyterlab_table",
20 | "extension:enable": "jupyter nbextension enable --py --sys-prefix jupyterlab_table",
21 | "extension:disable": "jupyter nbextension disable --py --sys-prefix jupyterlab_table"
22 | },
23 | "dependencies": {
24 | "react": "^15.3.2",
25 | "react-dom": "^15.3.2"
26 | },
27 | "devDependencies": {
28 | "babel-core": "^6.18.2",
29 | "babel-loader": "^6.4.0",
30 | "babel-preset-latest": "^6.16.0",
31 | "babel-preset-react": "^6.16.0",
32 | "babel-preset-stage-0": "^6.22.0",
33 | "css-loader": "^0.25.0",
34 | "file-loader": "^0.9.0",
35 | "json-loader": "^0.5.4",
36 | "style-loader": "^0.13.1",
37 | "url-loader": "^0.5.7",
38 | "watch": "^1.0.1",
39 | "webpack": "^2.2.0"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/labextension/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "name": "jupyterlab_table_labextension",
4 | "version": "0.18.0",
5 | "description": "A JupyterLab extension for rendering JSON Table Schema",
6 | "author": "Grant Nestor ",
7 | "main": "src/plugin.js",
8 | "keywords": [
9 | "jupyter",
10 | "jupyterlab",
11 | "jupyterlab extension"
12 | ],
13 | "scripts": {
14 | "build": "node build_extension.js",
15 | "watch": "watch \"npm install\" src ../component --wait 10 --ignoreDotFiles",
16 | "preinstall": "npm install ../component",
17 | "prepublish": "npm run build",
18 | "extension:install": "jupyter labextension install --symlink --py --sys-prefix jupyterlab_table",
19 | "extension:uninstall": "jupyter labextension uninstall --py --sys-prefix jupyterlab_table",
20 | "extension:enable": "jupyter labextension enable --py --sys-prefix jupyterlab_table",
21 | "extension:disable": "jupyter labextension disable --py --sys-prefix jupyterlab_table"
22 | },
23 | "dependencies": {
24 | "@jupyterlab/apputils": "^0.1.3",
25 | "@jupyterlab/codemirror": "^0.1.3",
26 | "@jupyterlab/docregistry": "^0.1.3",
27 | "@jupyterlab/rendermime": "^0.1.3",
28 | "@phosphor/algorithm": "^0.1.1",
29 | "@phosphor/virtualdom": "^0.1.1",
30 | "@phosphor/widgets": "^0.3.0",
31 | "react": "^15.3.2",
32 | "react-dom": "^15.3.2"
33 | },
34 | "devDependencies": {
35 | "@jupyterlab/extension-builder": "^0.10.0",
36 | "babel-core": "^6.18.2",
37 | "babel-loader": "^6.2.7",
38 | "babel-preset-latest": "^6.16.0",
39 | "babel-preset-react": "^6.16.0",
40 | "babel-preset-stage-0": "^6.16.0",
41 | "watch": "^1.0.1"
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/labextension/build_extension.js:
--------------------------------------------------------------------------------
1 | var buildExtension = require('@jupyterlab/extension-builder').buildExtension;
2 | var path = require('path');
3 |
4 | buildExtension({
5 | name: 'jupyterlab_table',
6 | entry: path.join(__dirname, 'src', 'plugin.js'),
7 | outputDir: path.join(
8 | __dirname,
9 | '..',
10 | 'jupyterlab_table',
11 | 'static'
12 | ),
13 | useDefaultLoaders: false,
14 | config: {
15 | module: {
16 | loaders: [
17 | { test: /\.html$/, loader: 'file-loader' },
18 | { test: /\.(jpg|png|gif)$/, loader: 'file-loader' },
19 | {
20 | test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
21 | loader: 'url-loader?limit=10000&mimetype=application/font-woff'
22 | },
23 | {
24 | test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
25 | loader: 'url-loader?limit=10000&mimetype=application/font-woff'
26 | },
27 | {
28 | test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
29 | loader: 'url-loader?limit=10000&mimetype=application/octet-stream'
30 | },
31 | { test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file-loader' },
32 | {
33 | test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
34 | loader: 'url-loader?limit=10000&mimetype=image/svg+xml'
35 | },
36 | { test: /\.json$/, loader: 'json-loader' },
37 | {
38 | test: /\.js$/,
39 | include: [
40 | path.join(__dirname, 'src'),
41 | path.join(
42 | __dirname,
43 | 'node_modules',
44 | 'jupyterlab_table_react'
45 | )
46 | ],
47 | loader: 'babel-loader',
48 | query: { presets: ['latest', 'stage-0', 'react'] }
49 | }
50 | ]
51 | }
52 | }
53 | });
54 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup
2 | from setupbase import create_cmdclass, install_npm
3 |
4 | cmdclass = create_cmdclass(['labextension', 'nbextension'])
5 | cmdclass['labextension'] = install_npm('labextension')
6 | cmdclass['nbextension'] = install_npm('nbextension')
7 |
8 | setup_args = dict(
9 | name = 'jupyterlab_table',
10 | version = '0.18.0',
11 | packages = ['jupyterlab_table'],
12 | author = 'Grant Nestor',
13 | author_email = 'grantnestor@gmail.com',
14 | url = 'http://jupyter.org',
15 | license = 'BSD',
16 | platforms = "Linux, Mac OS X, Windows",
17 | keywords = [
18 | 'ipython',
19 | 'jupyter',
20 | 'jupyterlab',
21 | 'extension',
22 | 'renderer',
23 | 'pandas',
24 | 'frictionlessdata',
25 | 'tableschema',
26 | 'dataresource'
27 | ],
28 | classifiers = [
29 | 'Intended Audience :: Developers',
30 | 'Intended Audience :: System Administrators',
31 | 'Intended Audience :: Science/Research',
32 | 'License :: OSI Approved :: BSD License',
33 | 'Programming Language :: Python',
34 | 'Programming Language :: Python :: 2.7',
35 | 'Programming Language :: Python :: 3',
36 | 'Programming Language :: Python :: 3.3',
37 | 'Programming Language :: Python :: 3.4',
38 | 'Programming Language :: Python :: 3.5',
39 | ],
40 | cmdclass = cmdclass,
41 | install_requires = [
42 | 'jupyterlab>=0.18.0',
43 | 'notebook>=4.3.0',
44 | 'ipython>=1.0.0'
45 | ]
46 | )
47 |
48 | if __name__ == '__main__':
49 | setup(**setup_args)
50 |
--------------------------------------------------------------------------------
/component/fixed-data-table.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | Table,
4 | Column,
5 | Cell
6 | } from 'fixed-data-table';
7 | import 'fixed-data-table/dist/fixed-data-table.min.css';
8 | // hack: `stream.Transform` (stream-browserify) is undefined in `csv-parse` when
9 | // built with @jupyterlabextension-builder
10 | import infer from 'jsontableschema/lib/infer';
11 | // import { infer } from 'jsontableschema';
12 | import './index.css';
13 |
14 | const ROW_HEIGHT = 34;
15 |
16 | function inferSchema(data) {
17 | const headers = data.reduce((result, row) => [...new Set([...result, ...Object.keys(row)])], []);
18 | const values = data.map(row => Object.values(row));
19 | return infer(headers, values);
20 | }
21 |
22 | export default class FixedDataTable extends React.Component {
23 |
24 | state = {
25 | columnWidths: {}
26 | }
27 |
28 | render() {
29 | let { schema, data } = this.props;
30 | if (!schema) schema = inferSchema(data);
31 | return (
32 | {
39 | this.setState(({columnWidths}) => ({
40 | columnWidths: {
41 | ...columnWidths,
42 | [columnKey]: columnWidth,
43 | }
44 | }));
45 | }}
46 | >
47 | {
48 | schema.fields.map((field, fieldIndex) =>
49 |
54 | | {field.name} |
55 | }
56 | cell={props =>
57 | {data[props.rowIndex][field.name]} |
58 | }
59 | fixed={false}
60 | isResizable={true}
61 | />
62 | )
63 | }
64 |
65 | );
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/install.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -e
3 | nbExtFlags=$1
4 |
5 | bash build.sh
6 |
7 | pip --version
8 | if [ $? -eq 0 ]; then
9 | echo pip is installed
10 | else
11 | echo "'pip --version' failed, therefore pip is not installed. In order to perform
12 | a developer install of jupyterlab_table you must have pip installed on
13 | your machine! See https://packaging.python.org/installing/ for installation instructions."
14 | exit 1
15 | fi
16 |
17 | pip install -v -e .
18 |
19 | jupyter lab --version
20 | if [ $? -eq 0 ]; then
21 | echo jupyter lab is installed
22 | if [[ "$OSTYPE" == "msys" ]]; then
23 | jupyter labextension install --py $nbExtFlags jupyterlab_table
24 | else
25 | jupyter labextension install --py --symlink $nbExtFlags jupyterlab_table
26 | fi
27 | jupyter labextension enable --py $nbExtFlags jupyterlab_table
28 | else
29 | echo "'jupyter lab --version' failed, therefore jupyter lab is not installed. In
30 | order to perform a developer install of jupyterlab_table you must
31 | have jupyter lab on your machine! Install using 'pip install jupyterlab' or
32 | follow instructions at https://github.com/jupyterlab/jupyterlab/blob/master/CONTRIBUTING.md#installing-jupyterlab for developer install."
33 | fi
34 |
35 | jupyter notebook --version
36 | if [ $? -eq 0 ]; then
37 | echo jupyter notebook is installed
38 | if [[ "$OSTYPE" == "msys" ]]; then
39 | jupyter nbextension install --py $nbExtFlags jupyterlab_table
40 | else
41 | jupyter nbextension install --py --symlink $nbExtFlags jupyterlab_table
42 | fi
43 | jupyter nbextension enable --py $nbExtFlags jupyterlab_table
44 | else
45 | echo "'jupyter notebook --version' failed, therefore jupyter notebook is not
46 | installed. In order to perform a developer install of
47 | jupyterlab_table you must have jupyter notebook on your machine!
48 | Install using 'pip install notebook' or follow instructions at
49 | https://github.com/jupyter/notebook/blob/master/CONTRIBUTING.rst#installing-the-jupyter-notebook
50 | for developer install."
51 | fi
52 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # jupyterlab_table
2 |
3 | A JupyterLab and Jupyter Notebook extension for rendering [JSON Table Schema](http://frictionlessdata.io/guides/json-table-schema/)
4 |
5 | 
6 |
7 | ## Prerequisites
8 |
9 | * JupyterLab ^0.18.0 and/or Notebook >=4.3.0
10 |
11 | ## Usage
12 |
13 | To render JSONTable output in IPython:
14 |
15 | ```python
16 | from jupyterlab_table import JSONTable
17 |
18 | JSONTable(data=[
19 | {
20 | "Date": "2000-03-01",
21 | "Adj Close": 33.68,
22 | "Open": 89.62,
23 | "Low": 88.94,
24 | "Volume": 106889800,
25 | "High": 94.09,
26 | "Close": 90.81
27 | },
28 | {
29 | "Date": "2000-03-02",
30 | "Adj Close": 34.63,
31 | "Open": 91.81,
32 | "Low": 91.12,
33 | "Volume": 106932600,
34 | "High": 95.37,
35 | "Close": 93.37
36 | }
37 | ], schema={
38 | "fields": [
39 | {
40 | "type": "any",
41 | "name": "Date"
42 | },
43 | {
44 | "type": "number",
45 | "name": "Open"
46 | },
47 | {
48 | "type": "number",
49 | "name": "High"
50 | },
51 | {
52 | "type": "number",
53 | "name": "Low"
54 | },
55 | {
56 | "type": "number",
57 | "name": "Close"
58 | },
59 | {
60 | "type": "integer",
61 | "name": "Volume"
62 | },
63 | {
64 | "type": "number",
65 | "name": "Adj Close"
66 | }
67 | ]
68 | })
69 | ```
70 |
71 | Using a pandas DataFrame:
72 |
73 | ```python
74 | from jupyterlab_table import JSONTable
75 | import pandas
76 | import numpy
77 |
78 | df = pandas.DataFrame(numpy.random.randn(2, 2))
79 | JSONTable(df)
80 | ```
81 |
82 | To render a .table.json file as a tree, simply open it:
83 |
84 | 
85 |
86 | ## Install
87 |
88 | ```bash
89 | pip install jupyterlab_table
90 | # For JupyterLab
91 | jupyter labextension install --symlink --py --sys-prefix jupyterlab_table
92 | jupyter labextension enable --py --sys-prefix jupyterlab_table
93 | # For Notebook
94 | jupyter nbextension install --symlink --py --sys-prefix jupyterlab_table
95 | jupyter nbextension enable --py --sys-prefix jupyterlab_table
96 | ```
97 |
98 | ## Development
99 |
100 | ```bash
101 | pip install -e .
102 | # For JupyterLab
103 | jupyter labextension install --symlink --py --sys-prefix jupyterlab_table
104 | jupyter labextension enable --py --sys-prefix jupyterlab_table
105 | # For Notebook
106 | jupyter nbextension install --symlink --py --sys-prefix jupyterlab_table
107 | jupyter nbextension enable --py --sys-prefix jupyterlab_table
108 | ```
109 |
--------------------------------------------------------------------------------
/labextension/src/output.js:
--------------------------------------------------------------------------------
1 | import { Widget } from '@phosphor/widgets';
2 | import React from 'react';
3 | import ReactDOM from 'react-dom';
4 | import ReactDOMServer from 'react-dom/server';
5 | import { VirtualizedGrid, VirtualizedTable } from 'jupyterlab_table_react';
6 |
7 | const MIME_TYPE = 'application/vnd.dataresource+json';
8 | const CLASS_NAME = 'jp-OutputWidgetJSONTable';
9 |
10 | /**
11 | * A Phosphor widget for rendering JSONTable
12 | */
13 | export class OutputWidget extends Widget {
14 | constructor(options) {
15 | super();
16 | this._mimeType = options.mimeType;
17 | this._data = options.model.data;
18 | this._metadata = options.model.metadata;
19 | this.addClass(CLASS_NAME);
20 | }
21 |
22 | /**
23 | * A message handler invoked on an `'after-attach'` message
24 | */
25 | onAfterAttach(msg) {
26 | /* Render initial data */
27 | this._render();
28 | }
29 |
30 | /**
31 | * A message handler invoked on an `'before-detach'` message
32 | */
33 | onBeforeDetach(msg) {
34 | /* Dispose of resources used by this widget */
35 | ReactDOM.unmountComponentAtNode(this.node);
36 | }
37 |
38 | /**
39 | * A message handler invoked on a `'child-added'` message
40 | */
41 | onChildAdded(msg) {
42 | /* e.g. Inject a static image representation into the mime bundle for
43 | * endering on Github, etc.
44 | */
45 | // renderLibrary.toPng(this.node).then(url => {
46 | // const data = url.split(',')[1];
47 | // this._data.set('image/png', data);
48 | // })
49 | }
50 |
51 | /**
52 | * A message handler invoked on a `'resize'` message
53 | */
54 | onResize(msg) {
55 | /* Re-render on resize */
56 | this._render();
57 | }
58 |
59 | /**
60 | * Render data to DOM node
61 | */
62 | _render() {
63 | const { data, schema } = this._data.get(this._mimeType);
64 | const metadata = this._metadata.get(this._mimeType);
65 | const type = metadata && metadata.format && metadata.format === 'table'
66 | ? VirtualizedTable
67 | : VirtualizedGrid;
68 | const props = {
69 | data,
70 | schema,
71 | metadata,
72 | width: this.node.offsetWidth,
73 | height: 360,
74 | fontSize: 13
75 | };
76 | ReactDOM.render(React.createElement(type, props), this.node);
77 | }
78 | }
79 |
80 | export class OutputRenderer {
81 | /**
82 | * The mime types that this OutputRenderer accepts
83 | */
84 | mimeTypes = [MIME_TYPE];
85 |
86 | /**
87 | * Whether the renderer can render given the render options
88 | */
89 | canRender(options) {
90 | return this.mimeTypes.indexOf(options.mimeType) !== -1;
91 | }
92 |
93 | /**
94 | * Render the transformed mime bundle
95 | */
96 | render(options) {
97 | return new OutputWidget(options);
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/labextension/src/plugin.js:
--------------------------------------------------------------------------------
1 | import { IRenderMime } from '@jupyterlab/rendermime';
2 | import { IDocumentRegistry } from '@jupyterlab/docregistry';
3 | import { ILayoutRestorer, InstanceTracker } from '@jupyterlab/apputils';
4 | import { toArray, ArrayExt } from '@phosphor/algorithm';
5 | import { OutputRenderer } from './output';
6 | import { DocWidgetFactory } from './doc';
7 | import './index.css';
8 |
9 | /**
10 | * The name of the factory
11 | */
12 | const FACTORY = 'JSONTable';
13 |
14 | /**
15 | * Set the extensions associated with application/vnd.dataresource+json
16 | */
17 | const EXTENSIONS = ['.tableschema.json', '.dataresource.json'];
18 | const DEFAULT_EXTENSIONS = ['.tableschema.json', '.dataresource.json'];
19 |
20 | /**
21 | * Activate the extension.
22 | */
23 | function activatePlugin(app, rendermime, registry, restorer) {
24 | /**
25 | * Calculate the index of the renderer in the array renderers
26 | * e.g. Insert this renderer after any renderers with mime type that matches
27 | * "+json"
28 | */
29 | // const index = ArrayExt.findLastIndex(
30 | // toArray(rendermime.mimeTypes()),
31 | // mime => mime.endsWith('+json')
32 | // ) + 1;
33 | /* ...or just insert it at the top */
34 | const index = 0;
35 |
36 | /**
37 | * Add output renderer for application/vnd.tableschema+json data
38 | */
39 | rendermime.addRenderer(
40 | {
41 | mimeType: 'application/vnd.tableschema+json',
42 | renderer: new OutputRenderer()
43 | },
44 | index
45 | );
46 |
47 | /**
48 | * Add output renderer for application/vnd.dataresource+json data
49 | */
50 | rendermime.addRenderer(
51 | {
52 | mimeType: 'application/vnd.dataresource+json',
53 | renderer: new OutputRenderer()
54 | },
55 | index
56 | );
57 |
58 | const factory = new DocWidgetFactory({
59 | fileExtensions: EXTENSIONS,
60 | defaultFor: DEFAULT_EXTENSIONS,
61 | name: FACTORY
62 | });
63 |
64 | /**
65 | * Add document renderer for .table.json files
66 | */
67 | registry.addWidgetFactory(factory);
68 |
69 | const tracker = new InstanceTracker({
70 | namespace: 'JSONTable',
71 | shell: app.shell
72 | });
73 |
74 | /**
75 | * Handle widget state deserialization
76 | */
77 | restorer.restore(tracker, {
78 | command: 'file-operations:open',
79 | args: widget => ({ path: widget.context.path, factory: FACTORY }),
80 | name: widget => widget.context.path
81 | });
82 |
83 | /**
84 | * Serialize widget state
85 | */
86 | factory.widgetCreated.connect((sender, widget) => {
87 | tracker.add(widget);
88 | /* Notify the instance tracker if restore data needs to update */
89 | widget.context.pathChanged.connect(() => {
90 | tracker.save(widget);
91 | });
92 | });
93 | }
94 |
95 | /**
96 | * Configure jupyterlab plugin
97 | */
98 | const Plugin = {
99 | id: 'jupyter.extensions.JSONTable',
100 | requires: [IRenderMime, IDocumentRegistry, ILayoutRestorer],
101 | activate: activatePlugin,
102 | autoStart: true
103 | };
104 |
105 | export default Plugin;
106 |
--------------------------------------------------------------------------------
/nbextension/webpack.config.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var version = require('./package.json').version;
3 |
4 | /**
5 | * Custom webpack loaders are generally the same for all webpack bundles, hence
6 | * stored in a separate local variable.
7 | */
8 | var loaders = [
9 | {
10 | test: /\.js$/,
11 | include: [
12 | path.join(__dirname, 'src'),
13 | path.join(__dirname, 'node_modules', 'jupyterlab_table_react')
14 | ],
15 | loader: 'babel-loader',
16 | query: { presets: [ 'latest', 'stage-0', 'react' ] }
17 | },
18 | { test: /\.json$/, loader: 'json-loader' },
19 | { test: /\.css$/, loader: 'style-loader!css-loader' },
20 | { test: /\.html$/, loader: 'file-loader' },
21 | { test: /\.(jpg|png|gif)$/, loader: 'file-loader' },
22 | {
23 | test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
24 | loader: 'url-loader?limit=10000&mimetype=application/font-woff'
25 | },
26 | {
27 | test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
28 | loader: 'url-loader?limit=10000&mimetype=application/font-woff'
29 | },
30 | {
31 | test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
32 | loader: 'url-loader?limit=10000&mimetype=application/octet-stream'
33 | },
34 | { test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file-loader' },
35 | {
36 | test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
37 | loader: 'url-loader?limit=10000&mimetype=image/svg+xml'
38 | }
39 | ];
40 |
41 | var base = {
42 | output: {
43 | libraryTarget: 'amd',
44 | devtoolModuleFilenameTemplate: 'webpack:///[absolute-resource-path]'
45 | },
46 | devtool: 'source-map',
47 | module: { loaders },
48 | externals: [
49 | 'nbextensions/jupyterlab_table/index',
50 | 'base/js/namespace',
51 | 'base/js/events',
52 | 'notebook/js/outputarea'
53 | ]
54 | };
55 |
56 | module.exports = [
57 | /**
58 | * Notebook extension
59 | *
60 | * This bundle only contains the part of the JavaScript that is run on
61 | * load of the notebook. This section generally only performs
62 | * some configuration for requirejs, and provides the legacy
63 | * "load_ipython_extension" function which is required for any notebook
64 | * extension.
65 | */
66 | Object.assign({}, base, {
67 | entry: path.join(__dirname, 'src', 'extension.js'),
68 | output: Object.assign({}, base.output, {
69 | filename: 'extension.js',
70 | path: path.join(
71 | __dirname,
72 | '..',
73 | 'jupyterlab_table',
74 | 'static'
75 | )
76 | })
77 | }),
78 | /**
79 | * Bundle for the notebook containing the custom widget views and models
80 | *
81 | * This bundle contains the implementation for the custom widget views and
82 | * custom widget.
83 | *
84 | * It must be an amd module
85 | */
86 | Object.assign({}, base, {
87 | entry: path.join(__dirname, 'src', 'index.js'),
88 | output: Object.assign({}, base.output, {
89 | filename: 'index.js',
90 | path: path.join(
91 | __dirname,
92 | '..',
93 | 'jupyterlab_table',
94 | 'static'
95 | )
96 | })
97 | }),
98 | /**
99 | * Embeddable jupyterlab_table bundle
100 | *
101 | * This bundle is generally almost identical to the notebook bundle
102 | * containing the custom widget views and models.
103 | *
104 | * The only difference is in the configuration of the webpack public path
105 | * for the static assets.
106 | *
107 | * It will be automatically distributed by unpkg to work with the static
108 | * widget embedder.
109 | *
110 | * The target bundle is always `lib/index.js`, which is the path required
111 | * by the custom widget embedder.
112 | */
113 | Object.assign({}, base, {
114 | entry: './src/embed.js',
115 | output: Object.assign({}, base.output, {
116 | filename: 'index.js',
117 | path: path.join(__dirname, 'embed'),
118 | publicPath: 'https://unpkg.com/jupyterlab_table@' +
119 | version +
120 | '/lib/'
121 | })
122 | })
123 | ];
124 |
--------------------------------------------------------------------------------
/labextension/src/doc.js:
--------------------------------------------------------------------------------
1 | import { Widget } from '@phosphor/widgets';
2 | import { ABCWidgetFactory } from '@jupyterlab/docregistry';
3 | import { ActivityMonitor } from '@jupyterlab/coreutils';
4 | import { runMode } from '@jupyterlab/codemirror';
5 | import React from 'react';
6 | import ReactDOM from 'react-dom';
7 | import { VirtualizedGrid, VirtualizedTable } from 'jupyterlab_table_react';
8 |
9 | const CLASS_NAME = 'jp-DocWidgetJSONTable';
10 | const RENDER_TIMEOUT = 1000;
11 |
12 | /**
13 | * A component for rendering error messages
14 | */
15 | class ErrorDisplay extends React.Component {
16 | componentDidUpdate() {
17 | runMode(this.props.content, { name: 'javascript', json: true }, this.ref);
18 | }
19 | render() {
20 | return (
21 |
22 |
{this.props.message}
23 |
{
25 | this.ref = ref;
26 | }}
27 | className="CodeMirror cm-s-jupyter CodeMirror-wrap"
28 | />
29 |
30 | );
31 | }
32 | }
33 |
34 | /**
35 | * A widget for rendering jupyterlab_table files
36 | */
37 | export class DocWidget extends Widget {
38 | constructor(context) {
39 | super();
40 | this._context = context;
41 | this._onPathChanged();
42 | this.addClass(CLASS_NAME);
43 | context.ready.then(() => {
44 | this.update();
45 | /* Re-render when the document content changes */
46 | context.model.contentChanged.connect(this.update, this);
47 | /* Re-render when the document path changes */
48 | context.fileChanged.connect(this.update, this);
49 | });
50 | /* Update title when path changes */
51 | context.pathChanged.connect(this._onPathChanged, this);
52 | /* Throttle re-renders until changes have stopped */
53 | this._monitor = new ActivityMonitor({
54 | signal: context.model.contentChanged,
55 | timeout: RENDER_TIMEOUT
56 | });
57 | this._monitor.activityStopped.connect(this.update, this);
58 | }
59 |
60 | /**
61 | * The widget's context
62 | */
63 | get context() {
64 | return this._context;
65 | }
66 |
67 | /**
68 | * Dispose of the resources used by the widget
69 | */
70 | dispose() {
71 | if (!this.isDisposed) {
72 | this._context = null;
73 | this._monitor.dispose();
74 | super.dispose();
75 | }
76 | }
77 |
78 | /**
79 | * A message handler invoked on an `'after-attach'` message
80 | */
81 | onAfterAttach(msg) {
82 | /* Render initial data */
83 | this.update();
84 | }
85 |
86 | /**
87 | * A message handler invoked on an `'before-detach'` message
88 | */
89 | onBeforeDetach(msg) {
90 | /* Dispose of resources used by widget */
91 | ReactDOM.unmountComponentAtNode(this.node);
92 | }
93 |
94 | /**
95 | * A message handler invoked on a `'resize'` message
96 | */
97 | onResize(msg) {
98 | /* Re-render on resize */
99 | this.update();
100 | }
101 |
102 | /**
103 | * A message handler invoked on an `'update-request'` message
104 | */
105 | onUpdateRequest(msg) {
106 | if (this.isAttached && this._context.isReady) this._render();
107 | }
108 |
109 | _render() {
110 | const content = this._context.model.toString();
111 | try {
112 | const { data, schema } = JSON.parse(content);
113 | const props = {
114 | data,
115 | schema,
116 | width: this.node.offsetWidth,
117 | height: this.node.offsetHeight,
118 | fontSize: 13
119 | };
120 | ReactDOM.render(, this.node);
121 | } catch (error) {
122 | ReactDOM.render(
123 | ,
124 | this.node
125 | );
126 | }
127 | }
128 |
129 | _onPathChanged() {
130 | this.title.label = this._context.path.split('/').pop();
131 | }
132 | }
133 |
134 | /**
135 | * A widget factory for DocWidget
136 | */
137 | export class DocWidgetFactory extends ABCWidgetFactory {
138 | /**
139 | * Create a new widget instance
140 | */
141 | createNewWidget(context) {
142 | return new DocWidget(context);
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/nbextension/src/renderer.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import ReactDOMServer from 'react-dom/server';
4 | import { VirtualizedGrid, VirtualizedTable } from 'jupyterlab_table_react';
5 | import './index.css';
6 |
7 | const MIME_TYPE = 'application/vnd.dataresource+json';
8 | const CLASS_NAME = 'output_JSONTable rendered_html';
9 | const DEFAULT_WIDTH = 840;
10 | const DEFAULT_HEIGHT = 360;
11 |
12 | /**
13 | * Render data to the DOM node
14 | */
15 | function render(props, node) {
16 | ReactDOM.render(, node);
17 | }
18 |
19 | /**
20 | * Handle when an output is cleared or removed
21 | */
22 | function handleClearOutput(event, { cell: { output_area } }) {
23 | /* Get rendered DOM node */
24 | const toinsert = output_area.element.find(`.${CLASS_NAME.split(' ')[0]}`);
25 | /* e.g. Dispose of resources used by renderer library */
26 | if (toinsert[0]) ReactDOM.unmountComponentAtNode(toinsert[0]);
27 | }
28 |
29 | /**
30 | * Handle when a new output is added
31 | */
32 | function handleAddOutput(event, { output, output_area }) {
33 | /* Get rendered DOM node */
34 | const toinsert = output_area.element.find(`.${CLASS_NAME.split(' ')[0]}`);
35 | /** e.g. Inject a static image representation into the mime bundle for
36 | * endering on Github, etc.
37 | */
38 | // if (toinsert[0]) {
39 | // renderLibrary.toPng(toinsert[0]).then(url => {
40 | // const data = url.split(',')[1];
41 | // output_area.outputs
42 | // .filter(output => output.data[MIME_TYPE])
43 | // .forEach(output => {
44 | // output.data['image/png'] = data;
45 | // });
46 | // });
47 | // }
48 | }
49 |
50 | /**
51 | * Register the mime type and append_mime function with the notebook's
52 | * output area
53 | */
54 | export function register_renderer(notebook, events, OutputArea) {
55 | /* A function to render output of 'application/vnd.dataresource+json' mime type */
56 | const append_mime = function(data, metadata, element) {
57 | /* Create a DOM node to render to */
58 | const toinsert = this.create_output_subarea(
59 | metadata,
60 | CLASS_NAME,
61 | MIME_TYPE
62 | );
63 | this.keyboard_manager.register_events(toinsert);
64 | const type = metadata[MIME_TYPE] &&
65 | metadata[MIME_TYPE].format &&
66 | metadata[MIME_TYPE].format === 'table'
67 | ? VirtualizedTable
68 | : VirtualizedGrid;
69 | const props = {
70 | ...data,
71 | metadata: metadata[MIME_TYPE],
72 | width: element.width(),
73 | height: DEFAULT_HEIGHT,
74 | fontSize: 14
75 | };
76 | ReactDOM.render(React.createElement(type, props), toinsert[0]);
77 | element.append(toinsert);
78 | const output_area = this;
79 | this.element.on('changed', () => {
80 | if (output_area.outputs.length > 0) ReactDOM.unmountComponentAtNode(toinsert[0]);
81 | });
82 | return toinsert;
83 | };
84 |
85 | /* Handle when an output is cleared or removed */
86 | events.on('clear_output.CodeCell', handleClearOutput);
87 | events.on('delete.Cell', handleClearOutput);
88 |
89 | /* Handle when a new output is added */
90 | events.on('output_added.OutputArea', handleAddOutput);
91 |
92 | /**
93 | * Calculate the index of this renderer in `output_area.display_order`
94 | * e.g. Insert this renderer after any renderers with mime type that matches
95 | * "+json"
96 | */
97 | // const mime_types = output_area.mime_types();
98 | // const json_types = mime_types.filter(mimetype => mimetype.includes('+json'));
99 | // const index = mime_types.lastIndexOf(json_types.pop() + 1);
100 |
101 | /* ...or just insert it at the top */
102 | const index = 0;
103 |
104 | /**
105 | * Register the mime type and append_mime function with output_area
106 | */
107 | OutputArea.prototype.register_mime_type(MIME_TYPE, append_mime, {
108 | /* Is output safe? */
109 | safe: true,
110 | /* Index of renderer in `output_area.display_order` */
111 | index: index
112 | });
113 | }
114 |
115 | /**
116 | * Re-render cells with output data of 'application/vnd.dataresource+json' mime type
117 | * on load notebook
118 | */
119 | export function render_cells(notebook) {
120 | /* Get all cells in notebook */
121 | notebook.get_cells().forEach(cell => {
122 | /* If a cell has output data of 'application/vnd.dataresource+json' mime type */
123 | if (
124 | cell.output_area &&
125 | cell.output_area.outputs.find(
126 | output => output.data && output.data[MIME_TYPE]
127 | )
128 | ) {
129 | /* Re-render the cell */
130 | notebook.render_cell_output(cell);
131 | }
132 | });
133 | }
134 |
--------------------------------------------------------------------------------
/component/virtualized-grid.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 | import React from 'react';
3 | import { MultiGrid, AutoSizer } from 'react-virtualized';
4 | // hack: `stream.Transform` (stream-browserify) is undefined in `csv-parse` when
5 | // built with @jupyterlabextension-builder
6 | import infer from 'jsontableschema/lib/infer';
7 | // import { infer } from 'jsontableschema';
8 | import './index.css';
9 |
10 | const ROW_HEIGHT = 36;
11 | const COLUMN_WIDTH = 72;
12 | const GRID_MAX_HEIGHT = ROW_HEIGHT * 10;
13 | // The width per text character for calculating widths for columns
14 | const COLUMN_CHARACTER_WIDTH = 14;
15 | // The number of sample rows that should be used to infer types for columns
16 | // and widths for columns
17 | const SAMPLE_SIZE = 10;
18 |
19 | type Props = {
20 | data: Array