瀏覽代碼

Ship vega4-extension by default. Fixes #6572

Dominik Moritz 5 年之前
父節點
當前提交
3fdc2d022e

+ 1 - 0
buildutils/src/ensure-repo.ts

@@ -29,6 +29,7 @@ let UNUSED: Dict<string[]> = {
   '@jupyterlab/services': ['node-fetch', 'ws'],
   '@jupyterlab/testutils': ['node-fetch', 'identity-obj-proxy'],
   '@jupyterlab/test-csvviewer': ['csv-spectrum'],
+  '@jupyterlab/vega4-extension': ['vega', 'vega-lite'],
   '@jupyterlab/vega5-extension': ['vega', 'vega-lite'],
   '@jupyterlab/ui-components': ['@blueprintjs/icons']
 };

+ 1 - 0
dev_mode/imports.css

@@ -33,4 +33,5 @@
 @import url('~@jupyterlab/terminal-extension/style/index.css');
 @import url('~@jupyterlab/tooltip-extension/style/index.css');
 @import url('~@jupyterlab/vdom-extension/style/index.css');
+@import url('~@jupyterlab/vega4-extension/style/index.css');
 @import url('~@jupyterlab/vega5-extension/style/index.css');

+ 3 - 0
dev_mode/package.json

@@ -64,6 +64,7 @@
     "@jupyterlab/tooltip": "^1.0.0-alpha.11",
     "@jupyterlab/tooltip-extension": "^1.0.0-alpha.11",
     "@jupyterlab/vdom-extension": "^1.0.0-alpha.11",
+    "@jupyterlab/vega4-extension": "^1.0.0-alpha.11",
     "@jupyterlab/vega5-extension": "^1.0.0-alpha.11",
     "@phosphor/algorithm": "^1.1.2",
     "@phosphor/application": "^1.6.0",
@@ -155,6 +156,7 @@
       "@jupyterlab/javascript-extension": "",
       "@jupyterlab/json-extension": "",
       "@jupyterlab/pdf-extension": "",
+      "@jupyterlab/vega4-extension": "",
       "@jupyterlab/vega5-extension": ""
     },
     "name": "JupyterLab",
@@ -249,6 +251,7 @@
       "@jupyterlab/theme-light-extension": "../packages/theme-light-extension",
       "@jupyterlab/tooltip-extension": "../packages/tooltip-extension",
       "@jupyterlab/vdom-extension": "../packages/vdom-extension",
+      "@jupyterlab/vega4-extension": "../packages/vega4-extension",
       "@jupyterlab/vega5-extension": "../packages/vega5-extension"
     }
   }

+ 1 - 0
packages/metapackage/src/index.ts

@@ -66,4 +66,5 @@ import '@jupyterlab/tooltip';
 import '@jupyterlab/tooltip-extension';
 import '@jupyterlab/ui-components';
 import '@jupyterlab/vdom-extension';
+import '@jupyterlab/vega4-extension';
 import '@jupyterlab/vega5-extension';

+ 3 - 0
packages/metapackage/tsconfig.json

@@ -222,6 +222,9 @@
     {
       "path": "../vdom-extension"
     },
+    {
+      "path": "../vega4-extension"
+    },
     {
       "path": "../vega5-extension"
     }

+ 107 - 0
packages/vega4-extension/README.md

@@ -0,0 +1,107 @@
+# vega4-extension
+
+A JupyterLab extension for rendering [Vega](https://vega.github.io/vega) 4 and [Vega-Lite](https://vega.github.io/vega-lite) 2.
+
+![demo](http://g.recordit.co/USoTkuCOfR.gif)
+
+## Prerequisites
+
+- JupyterLab ^0.27.0
+
+## Usage
+
+To render Vega-Lite output in IPython:
+
+```python
+from IPython.display import display
+
+display({
+    "application/vnd.vegalite.v2+json": {
+        "$schema": "https://vega.github.io/schema/vega-lite/v2.json",
+        "description": "A simple bar chart with embedded data.",
+        "data": {
+            "values": [
+                {"a": "A", "b": 28}, {"a": "B", "b": 55}, {"a": "C", "b": 43},
+                {"a": "D", "b": 91}, {"a": "E", "b": 81}, {"a": "F", "b": 53},
+                {"a": "G", "b": 19}, {"a": "H", "b": 87}, {"a": "I", "b": 52}
+            ]
+        },
+        "mark": "bar",
+        "encoding": {
+            "x": {"field": "a", "type": "ordinal"},
+            "y": {"field": "b", "type": "quantitative"}
+        }
+    }
+}, raw=True)
+```
+
+Using the [Altair library](https://github.com/altair-viz/altair):
+
+```python
+import altair as alt
+
+cars = alt.load_dataset('cars')
+
+chart = alt.Chart(cars).mark_point().encode(
+    x='Horsepower',
+    y='Miles_per_Gallon',
+    color='Origin',
+)
+
+chart
+```
+
+Provide Vega-Embed options via metadata:
+
+```python
+from IPython.display import display
+
+display({
+    "application/vnd.vegalite.v2+json": {
+        "$schema": "https://vega.github.io/schema/vega-lite/v2.json",
+        "description": "A simple bar chart with embedded data.",
+        "data": {
+            "values": [
+                {"a": "A", "b": 28}, {"a": "B", "b": 55}, {"a": "C", "b": 43},
+                {"a": "D", "b": 91}, {"a": "E", "b": 81}, {"a": "F", "b": 53},
+                {"a": "G", "b": 19}, {"a": "H", "b": 87}, {"a": "I", "b": 52}
+            ]
+        },
+        "mark": "bar",
+        "encoding": {
+            "x": {"field": "a", "type": "ordinal"},
+            "y": {"field": "b", "type": "quantitative"}
+        }
+    }
+}, metadata={
+    "application/vnd.vegalite.v2+json": {
+        "embed_options": {
+            "actions": False
+        }
+    }
+}, raw=True)
+```
+
+Provide Vega-Embed options via Altair:
+
+```python
+import altair as alt
+
+alt.renderers.enable('default', embed_options={'actions': False})
+
+cars = alt.load_dataset('cars')
+
+chart = alt.Chart(cars).mark_point().encode(
+    x='Horsepower',
+    y='Miles_per_Gallon',
+    color='Origin',
+)
+
+chart
+```
+
+To render a `.vl`, `.vg`, `vl.json` or `.vg.json` file, simply open it:
+
+## Development
+
+See the [JupyterLab Contributor Documentation](https://github.com/jupyterlab/jupyterlab/blob/master/CONTRIBUTING.md).

+ 56 - 0
packages/vega4-extension/package.json

@@ -0,0 +1,56 @@
+{
+  "name": "@jupyterlab/vega4-extension",
+  "version": "1.0.0-alpha.11",
+  "description": "JupyterLab - Vega 4 and Vega-Lite 2 Mime Renderer Extension",
+  "homepage": "https://github.com/jupyterlab/jupyterlab",
+  "bugs": {
+    "url": "https://github.com/jupyterlab/jupyterlab/issues"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/jupyterlab/jupyterlab.git"
+  },
+  "license": "BSD-3-Clause",
+  "author": "Project Jupyter",
+  "files": [
+    "lib/*.d.ts",
+    "lib/*.js",
+    "style/*.*"
+  ],
+  "sideEffects": [
+    "style/**/*"
+  ],
+  "main": "lib/index.js",
+  "types": "lib/index.d.ts",
+  "style": "style/index.css",
+  "directories": {
+    "lib": "lib/"
+  },
+  "scripts": {
+    "build": "tsc -b",
+    "clean": "rimraf lib",
+    "docs": "typedoc --options tdoptions.json --theme ../../typedoc-theme src",
+    "prepublishOnly": "npm run build",
+    "watch": "tsc -b --watch"
+  },
+  "dependencies": {
+    "@jupyterlab/rendermime-interfaces": "^1.3.0-alpha.11",
+    "@phosphor/coreutils": "^1.3.0",
+    "@phosphor/widgets": "^1.7.1",
+    "vega": "^4.4.0",
+    "vega-embed": "^4.2.0",
+    "vega-lite": "^2.6.0"
+  },
+  "devDependencies": {
+    "@types/webpack-env": "^1.13.9",
+    "rimraf": "~2.6.2",
+    "typedoc": "^0.14.2",
+    "typescript": "~3.5.1"
+  },
+  "publishConfig": {
+    "access": "public"
+  },
+  "jupyterlab": {
+    "mimeExtension": true
+  }
+}

+ 193 - 0
packages/vega4-extension/src/index.ts

@@ -0,0 +1,193 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) Jupyter Development Team.
+| Distributed under the terms of the Modified BSD License.
+|----------------------------------------------------------------------------*/
+
+import { JSONObject } from '@phosphor/coreutils';
+
+import { Widget } from '@phosphor/widgets';
+
+import { IRenderMime } from '@jupyterlab/rendermime-interfaces';
+
+import * as VegaModuleType from 'vega-embed';
+
+/**
+ * The CSS class to add to the Vega and Vega-Lite widget.
+ */
+const VEGA_COMMON_CLASS = 'jp-RenderedVegaCommon4';
+
+/**
+ * The CSS class to add to the Vega.
+ */
+const VEGA_CLASS = 'jp-RenderedVega4';
+
+/**
+ * The CSS class to add to the Vega-Lite.
+ */
+const VEGALITE_CLASS = 'jp-RenderedVegaLite2';
+
+/**
+ * The MIME type for Vega.
+ *
+ * #### Notes
+ * The version of this follows the major version of Vega.
+ */
+export const VEGA_MIME_TYPE = 'application/vnd.vega.v4+json';
+
+/**
+ * The MIME type for Vega-Lite.
+ *
+ * #### Notes
+ * The version of this follows the major version of Vega-Lite.
+ */
+export const VEGALITE_MIME_TYPE = 'application/vnd.vegalite.v2+json';
+
+/**
+ * A widget for rendering Vega or Vega-Lite data, for usage with rendermime.
+ */
+export class RenderedVega extends Widget implements IRenderMime.IRenderer {
+  private _result: VegaModuleType.Result;
+
+  /**
+   * Create a new widget for rendering Vega/Vega-Lite.
+   */
+  constructor(options: IRenderMime.IRendererOptions) {
+    super();
+    this._mimeType = options.mimeType;
+    this._resolver = options.resolver;
+    this.addClass(VEGA_COMMON_CLASS);
+    this.addClass(
+      this._mimeType === VEGA_MIME_TYPE ? VEGA_CLASS : VEGALITE_CLASS
+    );
+  }
+
+  /**
+   * Render Vega/Vega-Lite into this widget's node.
+   */
+  async renderModel(model: IRenderMime.IMimeModel): Promise<void> {
+    const spec = model.data[this._mimeType] as JSONObject;
+    const metadata = model.metadata[this._mimeType] as {
+      embed_options?: VegaModuleType.EmbedOptions;
+    };
+    const embedOptions =
+      metadata && metadata.embed_options ? metadata.embed_options : {};
+    const mode: VegaModuleType.Mode =
+      this._mimeType === VEGA_MIME_TYPE ? 'vega' : 'vega-lite';
+
+    const vega =
+      Private.vega != null ? Private.vega : await Private.ensureVega();
+    const path = await this._resolver.resolveUrl('');
+    const baseURL = await this._resolver.getDownloadUrl(path);
+
+    const el = document.createElement('div');
+
+    // clear the output before attaching a chart
+    this.node.textContent = '';
+    this.node.appendChild(el);
+
+    this._result = await vega.default(el, spec, {
+      actions: true,
+      defaultStyle: true,
+      ...embedOptions,
+      mode,
+      loader: {
+        baseURL,
+        http: { credentials: 'same-origin' }
+      }
+    });
+
+    if (model.data['image/png']) {
+      return;
+    }
+
+    // Add png representation of vega chart to output
+    const imageURL = await this._result.view.toImageURL('png');
+    model.setData({
+      data: { ...model.data, 'image/png': imageURL.split(',')[1] }
+    });
+  }
+
+  dispose(): void {
+    if (this._result) {
+      this._result.view.finalize();
+    }
+    super.dispose();
+  }
+
+  private _mimeType: string;
+  private _resolver: IRenderMime.IResolver;
+}
+
+/**
+ * A mime renderer factory for vega data.
+ */
+export const rendererFactory: IRenderMime.IRendererFactory = {
+  safe: true,
+  mimeTypes: [VEGA_MIME_TYPE, VEGALITE_MIME_TYPE],
+  createRenderer: options => new RenderedVega(options)
+};
+
+const extension: IRenderMime.IExtension = {
+  id: '@jupyterlab/vega4-extension:factory',
+  rendererFactory,
+  rank: 58,
+  dataType: 'json',
+  documentWidgetFactoryOptions: [
+    {
+      name: 'Vega',
+      primaryFileType: 'vega4',
+      fileTypes: ['vega4', 'json'],
+      defaultFor: ['vega4']
+    },
+    {
+      name: 'Vega-Lite',
+      primaryFileType: 'vega-lite2',
+      fileTypes: ['vega-lite2', 'json'],
+      defaultFor: ['vega-lite2']
+    }
+  ],
+  fileTypes: [
+    {
+      mimeTypes: [VEGA_MIME_TYPE],
+      name: 'vega4',
+      extensions: ['.vg', '.vg.json', '.vega'],
+      iconClass: 'jp-MaterialIcon jp-VegaIcon'
+    },
+    {
+      mimeTypes: [VEGALITE_MIME_TYPE],
+      name: 'vega-lite2',
+      extensions: ['.vl', '.vl.json', '.vegalite'],
+      iconClass: 'jp-MaterialIcon jp-VegaIcon'
+    }
+  ]
+};
+
+export default extension;
+
+/**
+ * A namespace for private module data.
+ */
+namespace Private {
+  /**
+   * A cached reference to the vega library.
+   */
+  export let vega: typeof VegaModuleType;
+
+  /**
+   * A Promise for the initial load of vega.
+   */
+  export let vegaReady: Promise<typeof VegaModuleType>;
+
+  /**
+   * Lazy-load and cache the vega-embed library
+   */
+  export function ensureVega(): Promise<typeof VegaModuleType> {
+    if (vegaReady) {
+      return vegaReady;
+    }
+
+    vegaReady = import('vega-embed');
+
+    return vegaReady;
+  }
+}

+ 3 - 0
packages/vega4-extension/src/json.d.ts

@@ -0,0 +1,3 @@
+declare module '*.json' {
+  export const version: string;
+}

+ 17 - 0
packages/vega4-extension/style/base.css

@@ -0,0 +1,17 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) Jupyter Development Team.
+| Distributed under the terms of the Modified BSD License.
+|----------------------------------------------------------------------------*/
+
+.jp-RenderedVegaCommon4 {
+  margin-left: 8px;
+  margin-top: 8px;
+}
+
+.jp-MimeDocument .jp-RenderedVegaCommon4 {
+  padding: 16px;
+}
+
+.vega canvas {
+  background: var(--jp-vega-background);
+}

+ 9 - 0
packages/vega4-extension/style/index.css

@@ -0,0 +1,9 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) Jupyter Development Team.
+| Distributed under the terms of the Modified BSD License.
+|----------------------------------------------------------------------------*/
+
+/* This file was auto-generated by ensurePackage() in @jupyterlab/buildutils */
+@import url('~@phosphor/widgets/style/index.css');
+
+@import url('./base.css');

+ 20 - 0
packages/vega4-extension/tdoptions.json

@@ -0,0 +1,20 @@
+{
+  "excludeNotExported": true,
+  "mode": "file",
+  "target": "es5",
+  "module": "es5",
+  "lib": [
+    "lib.es2015.d.ts",
+    "lib.es2015.collection.d.ts",
+    "lib.es2015.promise.d.ts",
+    "lib.dom.d.ts"
+  ],
+  "out": "../../docs/api/vega4-extension",
+  "baseUrl": ".",
+  "paths": {
+    "@jupyterlab/*": ["../packages/*"]
+  },
+  "esModuleInterop": true,
+  "jsx": "react",
+  "types": ["webpack-env"]
+}

+ 14 - 0
packages/vega4-extension/tsconfig.json

@@ -0,0 +1,14 @@
+{
+  "extends": "../../tsconfigbase",
+  "compilerOptions": {
+    "outDir": "lib",
+    "types": ["webpack-env"],
+    "rootDir": "src"
+  },
+  "include": ["src/*"],
+  "references": [
+    {
+      "path": "../rendermime-interfaces"
+    }
+  ]
+}

+ 3 - 3
packages/vega5-extension/README.md

@@ -35,7 +35,7 @@ display({
 }, raw=True)
 ```
 
-Using the [altair library](https://github.com/altair-viz/altair):
+Using the [Altair library](https://github.com/altair-viz/altair):
 
 ```python
 import altair as alt
@@ -51,7 +51,7 @@ chart = alt.Chart(cars).mark_point().encode(
 chart
 ```
 
-Provide vega-embed options via metadata:
+Provide Vega-Embed options via metadata:
 
 ```python
 from IPython.display import display
@@ -82,7 +82,7 @@ display({
 }, raw=True)
 ```
 
-Provide vega-embed options via altair:
+Provide Vega-Embed options via Altair:
 
 ```python
 import altair as alt

+ 3 - 3
packages/vega5-extension/package.json

@@ -37,9 +37,9 @@
     "@jupyterlab/rendermime-interfaces": "^1.3.0-alpha.11",
     "@phosphor/coreutils": "^1.3.0",
     "@phosphor/widgets": "^1.7.1",
-    "vega": "^5.3.5",
-    "vega-embed": "^4.0.0",
-    "vega-lite": "^3.2.1"
+    "vega": "^5.4.0",
+    "vega-embed": "^4.2.0",
+    "vega-lite": "^3.3.0"
   },
   "devDependencies": {
     "@types/webpack-env": "^1.13.9",

+ 1 - 1
packages/vega5-extension/src/index.ts

@@ -130,7 +130,7 @@ export const rendererFactory: IRenderMime.IRendererFactory = {
 const extension: IRenderMime.IExtension = {
   id: '@jupyterlab/vega5-extension:factory',
   rendererFactory,
-  rank: 50,
+  rank: 57,
   dataType: 'json',
   documentWidgetFactoryOptions: [
     {