@datalayer/jupyter-react 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +56 -0
- package/lib/examples/Example.d.ts +1 -0
- package/lib/examples/Example.js +8 -0
- package/lib/examples/Example.js.map +1 -0
- package/lib/examples/MuiSetup.d.ts +5 -0
- package/lib/examples/MuiSetup.js +13 -0
- package/lib/examples/MuiSetup.js.map +1 -0
- package/lib/examples/bootstrap/All.bootstrap.d.ts +1 -0
- package/lib/examples/bootstrap/All.bootstrap.js +84 -0
- package/lib/examples/bootstrap/All.bootstrap.js.map +1 -0
- package/lib/examples/bootstrap/Cell.bootstrap.d.ts +1 -0
- package/lib/examples/bootstrap/Cell.bootstrap.js +12 -0
- package/lib/examples/bootstrap/Cell.bootstrap.js.map +1 -0
- package/lib/examples/bootstrap/FileBrowser.bootstrap.d.ts +1 -0
- package/lib/examples/bootstrap/FileBrowser.bootstrap.js +10 -0
- package/lib/examples/bootstrap/FileBrowser.bootstrap.js.map +1 -0
- package/lib/examples/bootstrap/Gallery.bootstrap.d.ts +1 -0
- package/lib/examples/bootstrap/Gallery.bootstrap.js +18 -0
- package/lib/examples/bootstrap/Gallery.bootstrap.js.map +1 -0
- package/lib/examples/bootstrap/IPyWidgets.bootstrap.d.ts +1 -0
- package/lib/examples/bootstrap/IPyWidgets.bootstrap.js +12 -0
- package/lib/examples/bootstrap/IPyWidgets.bootstrap.js.map +1 -0
- package/lib/examples/bootstrap/Lumino.bootstrap.d.ts +1 -0
- package/lib/examples/bootstrap/Lumino.bootstrap.js +11 -0
- package/lib/examples/bootstrap/Lumino.bootstrap.js.map +1 -0
- package/lib/examples/bootstrap/Notebook.bootstrap.d.ts +1 -0
- package/lib/examples/bootstrap/Notebook.bootstrap.js +22 -0
- package/lib/examples/bootstrap/Notebook.bootstrap.js.map +1 -0
- package/lib/examples/bootstrap/NotebookCustom.bootstrap.d.ts +1 -0
- package/lib/examples/bootstrap/NotebookCustom.bootstrap.js +7 -0
- package/lib/examples/bootstrap/NotebookCustom.bootstrap.js.map +1 -0
- package/lib/examples/bootstrap/Outputs.bootstrap.d.ts +1 -0
- package/lib/examples/bootstrap/Outputs.bootstrap.js +154 -0
- package/lib/examples/bootstrap/Outputs.bootstrap.js.map +1 -0
- package/lib/examples/bootstrap/Terminal.bootstrap.d.ts +1 -0
- package/lib/examples/bootstrap/Terminal.bootstrap.js +13 -0
- package/lib/examples/bootstrap/Terminal.bootstrap.js.map +1 -0
- package/lib/examples/controls/CellControl.d.ts +3 -0
- package/lib/examples/controls/CellControl.js +15 -0
- package/lib/examples/controls/CellControl.js.map +1 -0
- package/lib/examples/controls/CommandsControl.d.ts +3 -0
- package/lib/examples/controls/CommandsControl.js +12 -0
- package/lib/examples/controls/CommandsControl.js.map +1 -0
- package/lib/examples/controls/ConsoleControl.d.ts +3 -0
- package/lib/examples/controls/ConsoleControl.js +12 -0
- package/lib/examples/controls/ConsoleControl.js.map +1 -0
- package/lib/examples/controls/DialogControl.d.ts +2 -0
- package/lib/examples/controls/DialogControl.js +7 -0
- package/lib/examples/controls/DialogControl.js.map +1 -0
- package/lib/examples/controls/FileBrowserControl.d.ts +3 -0
- package/lib/examples/controls/FileBrowserControl.js +12 -0
- package/lib/examples/controls/FileBrowserControl.js.map +1 -0
- package/lib/examples/controls/InitControl.d.ts +2 -0
- package/lib/examples/controls/InitControl.js +7 -0
- package/lib/examples/controls/InitControl.js.map +1 -0
- package/lib/examples/controls/NotebookControl.d.ts +3 -0
- package/lib/examples/controls/NotebookControl.js +16 -0
- package/lib/examples/controls/NotebookControl.js.map +1 -0
- package/lib/examples/controls/OutputControl.d.ts +3 -0
- package/lib/examples/controls/OutputControl.js +7 -0
- package/lib/examples/controls/OutputControl.js.map +1 -0
- package/lib/examples/controls/SettingsControl.d.ts +3 -0
- package/lib/examples/controls/SettingsControl.js +12 -0
- package/lib/examples/controls/SettingsControl.js.map +1 -0
- package/lib/examples/controls/SimpleControl.d.ts +2 -0
- package/lib/examples/controls/SimpleControl.js +7 -0
- package/lib/examples/controls/SimpleControl.js.map +1 -0
- package/lib/examples/controls/TerminalControl.d.ts +3 -0
- package/lib/examples/controls/TerminalControl.js +22 -0
- package/lib/examples/controls/TerminalControl.js.map +1 -0
- package/lib/examples/examples/cell/CellExample.d.ts +2 -0
- package/lib/examples/examples/cell/CellExample.js +42 -0
- package/lib/examples/examples/cell/CellExample.js.map +1 -0
- package/lib/examples/examples/gallery/GalleryExample.d.ts +2 -0
- package/lib/examples/examples/gallery/GalleryExample.js +154 -0
- package/lib/examples/examples/gallery/GalleryExample.js.map +1 -0
- package/lib/examples/examples/ipywidgets/IpyWidgetsExample.d.ts +4 -0
- package/lib/examples/examples/ipywidgets/IpyWidgetsExample.js +156 -0
- package/lib/examples/examples/ipywidgets/IpyWidgetsExample.js.map +1 -0
- package/lib/examples/examples/lumino/LuminoAdapter.css +34 -0
- package/lib/examples/examples/lumino/LuminoAdapter.d.ts +9 -0
- package/lib/examples/examples/lumino/LuminoAdapter.js +70 -0
- package/lib/examples/examples/lumino/LuminoAdapter.js.map +1 -0
- package/lib/examples/examples/lumino/LuminoExample.d.ts +2 -0
- package/lib/examples/examples/lumino/LuminoExample.js +10 -0
- package/lib/examples/examples/lumino/LuminoExample.js.map +1 -0
- package/lib/examples/examples/notebook/NotebookCustomHeader.d.ts +2 -0
- package/lib/examples/examples/notebook/NotebookCustomHeader.js +39 -0
- package/lib/examples/examples/notebook/NotebookCustomHeader.js.map +1 -0
- package/lib/examples/examples/notebook/NotebookExample.d.ts +1 -0
- package/lib/examples/examples/notebook/NotebookExample.js +24 -0
- package/lib/examples/examples/notebook/NotebookExample.js.map +1 -0
- package/lib/examples/theme/Layers.d.ts +2 -0
- package/lib/examples/theme/Layers.js +15 -0
- package/lib/examples/theme/Layers.js.map +1 -0
- package/lib/examples/theme/Layers.svg +14 -0
- package/lib/examples/theme/muiLightTheme.d.ts +8 -0
- package/lib/examples/theme/muiLightTheme.js +169 -0
- package/lib/examples/theme/muiLightTheme.js.map +1 -0
- package/lib/examples/theme/vintage.project.json +172 -0
- package/lib/examples/theme/westeros.project.json +168 -0
- package/lib/examples/theme/wonderland.project.json +168 -0
- package/lib/index.d.ts +31 -0
- package/lib/index.js +45 -0
- package/lib/index.js.map +1 -0
- package/lib/ipywidgets/IPyWidgetsAttached.d.ts +8 -0
- package/lib/ipywidgets/IPyWidgetsAttached.js +15 -0
- package/lib/ipywidgets/IPyWidgetsAttached.js.map +1 -0
- package/lib/ipywidgets/IPyWidgetsClassicManager.d.ts +18 -0
- package/lib/ipywidgets/IPyWidgetsClassicManager.js +76 -0
- package/lib/ipywidgets/IPyWidgetsClassicManager.js.map +1 -0
- package/lib/ipywidgets/IPyWidgetsJupyterLabPlugin.d.ts +15 -0
- package/lib/ipywidgets/IPyWidgetsJupyterLabPlugin.js +178 -0
- package/lib/ipywidgets/IPyWidgetsJupyterLabPlugin.js.map +1 -0
- package/lib/ipywidgets/IpyWidgetsComponent.d.ts +4 -0
- package/lib/ipywidgets/IpyWidgetsComponent.js +9 -0
- package/lib/ipywidgets/IpyWidgetsComponent.js.map +1 -0
- package/lib/ipywidgets/IpyWidgetsManager.d.ts +11 -0
- package/lib/ipywidgets/IpyWidgetsManager.js +71 -0
- package/lib/ipywidgets/IpyWidgetsManager.js.map +1 -0
- package/lib/ipywidgets/plotly/Figure.d.ts +587 -0
- package/lib/ipywidgets/plotly/Figure.js +1697 -0
- package/lib/ipywidgets/plotly/Figure.js.map +1 -0
- package/lib/ipywidgets/plotly/index.d.ts +2 -0
- package/lib/ipywidgets/plotly/index.js +4 -0
- package/lib/ipywidgets/plotly/index.js.map +1 -0
- package/lib/ipywidgets/plotly/jupyterlab-plugin.d.ts +5 -0
- package/lib/ipywidgets/plotly/jupyterlab-plugin.js +12 -0
- package/lib/ipywidgets/plotly/jupyterlab-plugin.js.map +1 -0
- package/lib/ipywidgets/plotly/version.d.ts +8 -0
- package/lib/ipywidgets/plotly/version.js +16 -0
- package/lib/ipywidgets/plotly/version.js.map +1 -0
- package/lib/jupyter/AuthError.d.ts +7 -0
- package/lib/jupyter/AuthError.js +8 -0
- package/lib/jupyter/AuthError.js.map +1 -0
- package/lib/jupyter/Handlers.d.ts +8 -0
- package/lib/jupyter/Handlers.js +50 -0
- package/lib/jupyter/Handlers.js.map +1 -0
- package/lib/jupyter/Jupyter.d.ts +23 -0
- package/lib/jupyter/Jupyter.js +35 -0
- package/lib/jupyter/Jupyter.js.map +1 -0
- package/lib/jupyter/JupyterConfig.d.ts +37 -0
- package/lib/jupyter/JupyterConfig.js +59 -0
- package/lib/jupyter/JupyterConfig.js.map +1 -0
- package/lib/jupyter/JupyterContext.d.ts +35 -0
- package/lib/jupyter/JupyterContext.js +64 -0
- package/lib/jupyter/JupyterContext.js.map +1 -0
- package/lib/lumino/LuminoAttached.d.ts +9 -0
- package/lib/lumino/LuminoAttached.js +23 -0
- package/lib/lumino/LuminoAttached.js.map +1 -0
- package/lib/lumino/LuminoDetached.d.ts +9 -0
- package/lib/lumino/LuminoDetached.js +13 -0
- package/lib/lumino/LuminoDetached.js.map +1 -0
- package/lib/lumino/LuminoObservable.d.ts +6 -0
- package/lib/lumino/LuminoObservable.js +16 -0
- package/lib/lumino/LuminoObservable.js.map +1 -0
- package/lib/lumino/LuminoReactPortal.d.ts +180 -0
- package/lib/lumino/LuminoReactPortal.js +195 -0
- package/lib/lumino/LuminoReactPortal.js.map +1 -0
- package/lib/lumino/LuminoRedux.d.ts +8 -0
- package/lib/lumino/LuminoRedux.js +2 -0
- package/lib/lumino/LuminoRedux.js.map +1 -0
- package/lib/services/Services.d.ts +17 -0
- package/lib/services/Services.js +41 -0
- package/lib/services/Services.js.map +1 -0
- package/lib/services/kernel/Kernel.d.ts +18 -0
- package/lib/services/kernel/Kernel.js +95 -0
- package/lib/services/kernel/Kernel.js.map +1 -0
- package/lib/services/kernel/KernelModel.d.ts +18 -0
- package/lib/services/kernel/KernelModel.js +52 -0
- package/lib/services/kernel/KernelModel.js.map +1 -0
- package/lib/state/AllState.d.ts +8 -0
- package/lib/state/AllState.js +24 -0
- package/lib/state/AllState.js.map +1 -0
- package/lib/state/InjectableStore.d.ts +9 -0
- package/lib/state/InjectableStore.js +27 -0
- package/lib/state/InjectableStore.js.map +1 -0
- package/lib/state/init/Init.d.ts +3 -0
- package/lib/state/init/Init.js +12 -0
- package/lib/state/init/Init.js.map +1 -0
- package/lib/state/init/InitRedux.d.ts +21 -0
- package/lib/state/init/InitRedux.js +50 -0
- package/lib/state/init/InitRedux.js.map +1 -0
- package/lib/widgets/cell/CellAdapter.css +16 -0
- package/lib/widgets/cell/CellAdapter.d.ts +18 -0
- package/lib/widgets/cell/CellAdapter.js +160 -0
- package/lib/widgets/cell/CellAdapter.js.map +1 -0
- package/lib/widgets/cell/CellLumino.d.ts +9 -0
- package/lib/widgets/cell/CellLumino.js +48 -0
- package/lib/widgets/cell/CellLumino.js.map +1 -0
- package/lib/widgets/cell/CellState.d.ts +22 -0
- package/lib/widgets/cell/CellState.js +79 -0
- package/lib/widgets/cell/CellState.js.map +1 -0
- package/lib/widgets/commands/CommandsAdapter.css +3 -0
- package/lib/widgets/commands/CommandsAdapter.d.ts +9 -0
- package/lib/widgets/commands/CommandsAdapter.js +36 -0
- package/lib/widgets/commands/CommandsAdapter.js.map +1 -0
- package/lib/widgets/commands/CommandsLumino.d.ts +2 -0
- package/lib/widgets/commands/CommandsLumino.js +9 -0
- package/lib/widgets/commands/CommandsLumino.js.map +1 -0
- package/lib/widgets/commands/CommandsState.d.ts +19 -0
- package/lib/widgets/commands/CommandsState.js +50 -0
- package/lib/widgets/commands/CommandsState.js.map +1 -0
- package/lib/widgets/console/ConsoleAdapter.css +4 -0
- package/lib/widgets/console/ConsoleAdapter.d.ts +11 -0
- package/lib/widgets/console/ConsoleAdapter.js +82 -0
- package/lib/widgets/console/ConsoleAdapter.js.map +1 -0
- package/lib/widgets/console/ConsoleLumino.d.ts +2 -0
- package/lib/widgets/console/ConsoleLumino.js +9 -0
- package/lib/widgets/console/ConsoleLumino.js.map +1 -0
- package/lib/widgets/console/ConsoleState.d.ts +19 -0
- package/lib/widgets/console/ConsoleState.js +50 -0
- package/lib/widgets/console/ConsoleState.js.map +1 -0
- package/lib/widgets/dialog/DialogAdapter.css +0 -0
- package/lib/widgets/dialog/DialogAdapter.d.ts +10 -0
- package/lib/widgets/dialog/DialogAdapter.js +19 -0
- package/lib/widgets/dialog/DialogAdapter.js.map +1 -0
- package/lib/widgets/dialog/DialogLumino.d.ts +2 -0
- package/lib/widgets/dialog/DialogLumino.js +13 -0
- package/lib/widgets/dialog/DialogLumino.js.map +1 -0
- package/lib/widgets/editor/CodeMirrorEditor.d.ts +7 -0
- package/lib/widgets/editor/CodeMirrorEditor.js +62 -0
- package/lib/widgets/editor/CodeMirrorEditor.js.map +1 -0
- package/lib/widgets/filebrowser/FileBrowser.d.ts +2 -0
- package/lib/widgets/filebrowser/FileBrowser.js +60 -0
- package/lib/widgets/filebrowser/FileBrowser.js.map +1 -0
- package/lib/widgets/filebrowser/FileBrowserAdapter.css +8 -0
- package/lib/widgets/filebrowser/FileBrowserAdapter.d.ts +13 -0
- package/lib/widgets/filebrowser/FileBrowserAdapter.js +267 -0
- package/lib/widgets/filebrowser/FileBrowserAdapter.js.map +1 -0
- package/lib/widgets/filebrowser/FileBrowserLumino.d.ts +2 -0
- package/lib/widgets/filebrowser/FileBrowserLumino.js +9 -0
- package/lib/widgets/filebrowser/FileBrowserLumino.js.map +1 -0
- package/lib/widgets/filebrowser/FileBrowserState.d.ts +19 -0
- package/lib/widgets/filebrowser/FileBrowserState.js +50 -0
- package/lib/widgets/filebrowser/FileBrowserState.js.map +1 -0
- package/lib/widgets/notebook/NotebookAdapter.css +27 -0
- package/lib/widgets/notebook/NotebookAdapter.d.ts +26 -0
- package/lib/widgets/notebook/NotebookAdapter.js +187 -0
- package/lib/widgets/notebook/NotebookAdapter.js.map +1 -0
- package/lib/widgets/notebook/NotebookCommands.d.ts +7 -0
- package/lib/widgets/notebook/NotebookCommands.js +349 -0
- package/lib/widgets/notebook/NotebookCommands.js.map +1 -0
- package/lib/widgets/notebook/NotebookLumino.d.ts +19 -0
- package/lib/widgets/notebook/NotebookLumino.js +75 -0
- package/lib/widgets/notebook/NotebookLumino.js.map +1 -0
- package/lib/widgets/notebook/NotebookState.d.ts +43 -0
- package/lib/widgets/notebook/NotebookState.js +114 -0
- package/lib/widgets/notebook/NotebookState.js.map +1 -0
- package/lib/widgets/notebook/NotebookToolbar.d.ts +2 -0
- package/lib/widgets/notebook/NotebookToolbar.js +24 -0
- package/lib/widgets/notebook/NotebookToolbar.js.map +1 -0
- package/lib/widgets/notebook/extension/CellSidebar.d.ts +7 -0
- package/lib/widgets/notebook/extension/CellSidebar.js +23 -0
- package/lib/widgets/notebook/extension/CellSidebar.js.map +1 -0
- package/lib/widgets/notebook/extension/CellSidebarDefault.d.ts +2 -0
- package/lib/widgets/notebook/extension/CellSidebarDefault.js +47 -0
- package/lib/widgets/notebook/extension/CellSidebarDefault.js.map +1 -0
- package/lib/widgets/notebook/extension/ContentFactoryWithSidebar.d.ts +14 -0
- package/lib/widgets/notebook/extension/ContentFactoryWithSidebar.js +20 -0
- package/lib/widgets/notebook/extension/ContentFactoryWithSidebar.js.map +1 -0
- package/lib/widgets/notebook/extension/NotebookInputPrompt.d.ts +21 -0
- package/lib/widgets/notebook/extension/NotebookInputPrompt.js +67 -0
- package/lib/widgets/notebook/extension/NotebookInputPrompt.js.map +1 -0
- package/lib/widgets/outputs/OutputAdapter.css +0 -0
- package/lib/widgets/outputs/OutputAdapter.d.ts +21 -0
- package/lib/widgets/outputs/OutputAdapter.js +75 -0
- package/lib/widgets/outputs/OutputAdapter.js.map +1 -0
- package/lib/widgets/outputs/OutputLumino.d.ts +16 -0
- package/lib/widgets/outputs/OutputLumino.js +56 -0
- package/lib/widgets/outputs/OutputLumino.js.map +1 -0
- package/lib/widgets/outputs/OutputState.d.ts +19 -0
- package/lib/widgets/outputs/OutputState.js +50 -0
- package/lib/widgets/outputs/OutputState.js.map +1 -0
- package/lib/widgets/settings/SettingsAdapter.css +0 -0
- package/lib/widgets/settings/SettingsAdapter.d.ts +10 -0
- package/lib/widgets/settings/SettingsAdapter.js +16 -0
- package/lib/widgets/settings/SettingsAdapter.js.map +1 -0
- package/lib/widgets/settings/SettingsLumino.d.ts +2 -0
- package/lib/widgets/settings/SettingsLumino.js +11 -0
- package/lib/widgets/settings/SettingsLumino.js.map +1 -0
- package/lib/widgets/settings/SettingsState.d.ts +19 -0
- package/lib/widgets/settings/SettingsState.js +50 -0
- package/lib/widgets/settings/SettingsState.js.map +1 -0
- package/lib/widgets/terminal/TerminalAdapter.css +3 -0
- package/lib/widgets/terminal/TerminalAdapter.d.ts +13 -0
- package/lib/widgets/terminal/TerminalAdapter.js +28 -0
- package/lib/widgets/terminal/TerminalAdapter.js.map +1 -0
- package/lib/widgets/terminal/TerminalLumino.d.ts +2 -0
- package/lib/widgets/terminal/TerminalLumino.js +17 -0
- package/lib/widgets/terminal/TerminalLumino.js.map +1 -0
- package/lib/widgets/terminal/TerminalState.d.ts +17 -0
- package/lib/widgets/terminal/TerminalState.js +45 -0
- package/lib/widgets/terminal/TerminalState.js.map +1 -0
- package/package.json +163 -0
- package/style/index.css +3 -0
|
@@ -0,0 +1,1697 @@
|
|
|
1
|
+
import { DOMWidgetModel, DOMWidgetView, } from "@jupyter-widgets/base";
|
|
2
|
+
import _ from "lodash";
|
|
3
|
+
import Plotly from "plotly.js";
|
|
4
|
+
import { MODULE_NAME, MODULE_VERSION } from "./version";
|
|
5
|
+
// @ts-ignore
|
|
6
|
+
window.PlotlyConfig = { MathJaxConfig: "local" };
|
|
7
|
+
const semver_range = "^" + MODULE_VERSION;
|
|
8
|
+
// Model
|
|
9
|
+
// =====
|
|
10
|
+
/**
|
|
11
|
+
* A FigureModel holds a mirror copy of the state of a FigureWidget on
|
|
12
|
+
* the Python side. There is a one-to-one relationship between JavaScript
|
|
13
|
+
* FigureModels and Python FigureWidgets. The JavaScript FigureModel is
|
|
14
|
+
* initialized as soon as a Python FigureWidget initialized, this happens
|
|
15
|
+
* even before the widget is first displayed in the Notebook
|
|
16
|
+
* @type {widgets.DOMWidgetModel}
|
|
17
|
+
*/
|
|
18
|
+
export class FigureModel extends DOMWidgetModel {
|
|
19
|
+
defaults() {
|
|
20
|
+
return Object.assign(Object.assign({}, super.defaults()), {
|
|
21
|
+
// Model metadata
|
|
22
|
+
// --------------
|
|
23
|
+
_model_name: FigureModel.model_name, _model_module: FigureModel.model_module, _model_module_version: FigureModel.model_module_version, _view_name: FigureModel.view_name, _view_module: FigureModel.view_module, _view_module_version: FigureModel.view_module_version,
|
|
24
|
+
// Data and Layout
|
|
25
|
+
// ---------------
|
|
26
|
+
// The _data and _layout properties are synchronized with the
|
|
27
|
+
// Python side on initialization only. After initialization, these
|
|
28
|
+
// properties are kept in sync through the use of the _py2js_*
|
|
29
|
+
// messages
|
|
30
|
+
_data: [], _layout: {}, _config: {},
|
|
31
|
+
// Python -> JS messages
|
|
32
|
+
// ---------------------
|
|
33
|
+
// Messages are implemented using trait properties. This is done so
|
|
34
|
+
// that we can take advantage of ipywidget's binary serialization
|
|
35
|
+
// protocol.
|
|
36
|
+
//
|
|
37
|
+
// Messages are sent by the Python side by assigning the message
|
|
38
|
+
// contents to the appropriate _py2js_* property, and then immediately
|
|
39
|
+
// setting it to None. Messages are received by the JavaScript
|
|
40
|
+
// side by registering property change callbacks in the initialize
|
|
41
|
+
// methods for FigureModel and FigureView. e.g. (where this is a
|
|
42
|
+
// FigureModel):
|
|
43
|
+
//
|
|
44
|
+
// this.on('change:_py2js_addTraces', this.do_addTraces, this);
|
|
45
|
+
//
|
|
46
|
+
// Message handling methods, do_addTraces, are responsible for
|
|
47
|
+
// performing the appropriate action if the message contents are
|
|
48
|
+
// not null
|
|
49
|
+
/**
|
|
50
|
+
* @typedef {null|Object} Py2JsAddTracesMsg
|
|
51
|
+
* @property {Array.<Object>} trace_data
|
|
52
|
+
* Array of traces to append to the end of the figure's current traces
|
|
53
|
+
* @property {Number} trace_edit_id
|
|
54
|
+
* Edit ID to use when returning trace deltas using
|
|
55
|
+
* the _js2py_traceDeltas message.
|
|
56
|
+
* @property {Number} layout_edit_id
|
|
57
|
+
* Edit ID to use when returning layout deltas using
|
|
58
|
+
* the _js2py_layoutDelta message.
|
|
59
|
+
*/
|
|
60
|
+
_py2js_addTraces: null,
|
|
61
|
+
/**
|
|
62
|
+
* @typedef {null|Object} Py2JsDeleteTracesMsg
|
|
63
|
+
* @property {Array.<Number>} delete_inds
|
|
64
|
+
* Array of indexes of traces to be deleted, in ascending order
|
|
65
|
+
* @property {Number} trace_edit_id
|
|
66
|
+
* Edit ID to use when returning trace deltas using
|
|
67
|
+
* the _js2py_traceDeltas message.
|
|
68
|
+
* @property {Number} layout_edit_id
|
|
69
|
+
* Edit ID to use when returning layout deltas using
|
|
70
|
+
* the _js2py_layoutDelta message.
|
|
71
|
+
*/
|
|
72
|
+
_py2js_deleteTraces: null,
|
|
73
|
+
/**
|
|
74
|
+
* @typedef {null|Object} Py2JsMoveTracesMsg
|
|
75
|
+
* @property {Array.<Number>} current_trace_inds
|
|
76
|
+
* Array of the current indexes of traces to be moved
|
|
77
|
+
* @property {Array.<Number>} new_trace_inds
|
|
78
|
+
* Array of the new indexes that traces should be moved to.
|
|
79
|
+
*/
|
|
80
|
+
_py2js_moveTraces: null,
|
|
81
|
+
/**
|
|
82
|
+
* @typedef {null|Object} Py2JsRestyleMsg
|
|
83
|
+
* @property {Object} restyle_data
|
|
84
|
+
* Restyle data as accepted by Plotly.restyle
|
|
85
|
+
* @property {null|Array.<Number>} restyle_traces
|
|
86
|
+
* Array of indexes of the traces that the resytle operation applies
|
|
87
|
+
* to, or null to apply the operation to all traces
|
|
88
|
+
* @property {Number} trace_edit_id
|
|
89
|
+
* Edit ID to use when returning trace deltas using
|
|
90
|
+
* the _js2py_traceDeltas message
|
|
91
|
+
* @property {Number} layout_edit_id
|
|
92
|
+
* Edit ID to use when returning layout deltas using
|
|
93
|
+
* the _js2py_layoutDelta message
|
|
94
|
+
* @property {null|String} source_view_id
|
|
95
|
+
* view_id of the FigureView that triggered the original restyle
|
|
96
|
+
* event (e.g. by clicking the legend), or null if the restyle was
|
|
97
|
+
* triggered from Python
|
|
98
|
+
*/
|
|
99
|
+
_py2js_restyle: null,
|
|
100
|
+
/**
|
|
101
|
+
* @typedef {null|Object} Py2JsRelayoutMsg
|
|
102
|
+
* @property {Object} relayout_data
|
|
103
|
+
* Relayout data as accepted by Plotly.relayout
|
|
104
|
+
* @property {Number} layout_edit_id
|
|
105
|
+
* Edit ID to use when returning layout deltas using
|
|
106
|
+
* the _js2py_layoutDelta message
|
|
107
|
+
* @property {null|String} source_view_id
|
|
108
|
+
* view_id of the FigureView that triggered the original relayout
|
|
109
|
+
* event (e.g. by clicking the zoom button), or null if the
|
|
110
|
+
* relayout was triggered from Python
|
|
111
|
+
*/
|
|
112
|
+
_py2js_relayout: null,
|
|
113
|
+
/**
|
|
114
|
+
* @typedef {null|Object} Py2JsUpdateMsg
|
|
115
|
+
* @property {Object} style_data
|
|
116
|
+
* Style data as accepted by Plotly.update
|
|
117
|
+
* @property {Object} layout_data
|
|
118
|
+
* Layout data as accepted by Plotly.update
|
|
119
|
+
* @property {Array.<Number>} style_traces
|
|
120
|
+
* Array of indexes of the traces that the update operation applies
|
|
121
|
+
* to, or null to apply the operation to all traces
|
|
122
|
+
* @property {Number} trace_edit_id
|
|
123
|
+
* Edit ID to use when returning trace deltas using
|
|
124
|
+
* the _js2py_traceDeltas message
|
|
125
|
+
* @property {Number} layout_edit_id
|
|
126
|
+
* Edit ID to use when returning layout deltas using
|
|
127
|
+
* the _js2py_layoutDelta message
|
|
128
|
+
* @property {null|String} source_view_id
|
|
129
|
+
* view_id of the FigureView that triggered the original update
|
|
130
|
+
* event (e.g. by clicking a button), or null if the update was
|
|
131
|
+
* triggered from Python
|
|
132
|
+
*/
|
|
133
|
+
_py2js_update: null,
|
|
134
|
+
/**
|
|
135
|
+
* @typedef {null|Object} Py2JsAnimateMsg
|
|
136
|
+
* @property {Object} style_data
|
|
137
|
+
* Style data as accepted by Plotly.animate
|
|
138
|
+
* @property {Object} layout_data
|
|
139
|
+
* Layout data as accepted by Plotly.animate
|
|
140
|
+
* @property {Array.<Number>} style_traces
|
|
141
|
+
* Array of indexes of the traces that the animate operation applies
|
|
142
|
+
* to, or null to apply the operation to all traces
|
|
143
|
+
* @property {Object} animation_opts
|
|
144
|
+
* Animation options as accepted by Plotly.animate
|
|
145
|
+
* @property {Number} trace_edit_id
|
|
146
|
+
* Edit ID to use when returning trace deltas using
|
|
147
|
+
* the _js2py_traceDeltas message
|
|
148
|
+
* @property {Number} layout_edit_id
|
|
149
|
+
* Edit ID to use when returning layout deltas using
|
|
150
|
+
* the _js2py_layoutDelta message
|
|
151
|
+
* @property {null|String} source_view_id
|
|
152
|
+
* view_id of the FigureView that triggered the original animate
|
|
153
|
+
* event (e.g. by clicking a button), or null if the update was
|
|
154
|
+
* triggered from Python
|
|
155
|
+
*/
|
|
156
|
+
_py2js_animate: null,
|
|
157
|
+
/**
|
|
158
|
+
* @typedef {null|Object} Py2JsRemoveLayoutPropsMsg
|
|
159
|
+
* @property {Array.<Array.<String|Number>>} remove_props
|
|
160
|
+
* Array of property paths to remove. Each propery path is an
|
|
161
|
+
* array of property names or array indexes that locate a property
|
|
162
|
+
* inside the _layout object
|
|
163
|
+
*/
|
|
164
|
+
_py2js_removeLayoutProps: null,
|
|
165
|
+
/**
|
|
166
|
+
* @typedef {null|Object} Py2JsRemoveTracePropsMsg
|
|
167
|
+
* @property {Number} remove_trace
|
|
168
|
+
* The index of the trace from which to remove properties
|
|
169
|
+
* @property {Array.<Array.<String|Number>>} remove_props
|
|
170
|
+
* Array of property paths to remove. Each propery path is an
|
|
171
|
+
* array of property names or array indexes that locate a property
|
|
172
|
+
* inside the _data[remove_trace] object
|
|
173
|
+
*/
|
|
174
|
+
_py2js_removeTraceProps: null,
|
|
175
|
+
// JS -> Python messages
|
|
176
|
+
// ---------------------
|
|
177
|
+
// Messages are sent by the JavaScript side by assigning the
|
|
178
|
+
// message contents to the appropriate _js2py_* property and then
|
|
179
|
+
// calling the `touch` method on the view that triggered the
|
|
180
|
+
// change. e.g. (where this is a FigureView):
|
|
181
|
+
//
|
|
182
|
+
// this.model.set('_js2py_restyle', data);
|
|
183
|
+
// this.touch();
|
|
184
|
+
//
|
|
185
|
+
// The Python side is responsible for setting the property to None
|
|
186
|
+
// after receiving the message.
|
|
187
|
+
//
|
|
188
|
+
// Message trigger logic is described in the corresponding
|
|
189
|
+
// handle_plotly_* methods of FigureView
|
|
190
|
+
/**
|
|
191
|
+
* @typedef {null|Object} Js2PyRestyleMsg
|
|
192
|
+
* @property {Object} style_data
|
|
193
|
+
* Style data that was passed to Plotly.restyle
|
|
194
|
+
* @property {Array.<Number>} style_traces
|
|
195
|
+
* Array of indexes of the traces that the restyle operation
|
|
196
|
+
* was applied to, or null if applied to all traces
|
|
197
|
+
* @property {String} source_view_id
|
|
198
|
+
* view_id of the FigureView that triggered the original restyle
|
|
199
|
+
* event (e.g. by clicking the legend)
|
|
200
|
+
*/
|
|
201
|
+
_js2py_restyle: null,
|
|
202
|
+
/**
|
|
203
|
+
* @typedef {null|Object} Js2PyRelayoutMsg
|
|
204
|
+
* @property {Object} relayout_data
|
|
205
|
+
* Relayout data that was passed to Plotly.relayout
|
|
206
|
+
* @property {String} source_view_id
|
|
207
|
+
* view_id of the FigureView that triggered the original relayout
|
|
208
|
+
* event (e.g. by clicking the zoom button)
|
|
209
|
+
*/
|
|
210
|
+
_js2py_relayout: null,
|
|
211
|
+
/**
|
|
212
|
+
* @typedef {null|Object} Js2PyUpdateMsg
|
|
213
|
+
* @property {Object} style_data
|
|
214
|
+
* Style data that was passed to Plotly.update
|
|
215
|
+
* @property {Object} layout_data
|
|
216
|
+
* Layout data that was passed to Plotly.update
|
|
217
|
+
* @property {Array.<Number>} style_traces
|
|
218
|
+
* Array of indexes of the traces that the update operation applied
|
|
219
|
+
* to, or null if applied to all traces
|
|
220
|
+
* @property {String} source_view_id
|
|
221
|
+
* view_id of the FigureView that triggered the original relayout
|
|
222
|
+
* event (e.g. by clicking the zoom button)
|
|
223
|
+
*/
|
|
224
|
+
_js2py_update: null,
|
|
225
|
+
/**
|
|
226
|
+
* @typedef {null|Object} Js2PyLayoutDeltaMsg
|
|
227
|
+
* @property {Object} layout_delta
|
|
228
|
+
* The layout delta object that contains all of the properties of
|
|
229
|
+
* _fullLayout that are not identical to those in the
|
|
230
|
+
* FigureModel's _layout property
|
|
231
|
+
* @property {Number} layout_edit_id
|
|
232
|
+
* Edit ID of message that triggered the creation of layout delta
|
|
233
|
+
*/
|
|
234
|
+
_js2py_layoutDelta: null,
|
|
235
|
+
/**
|
|
236
|
+
* @typedef {null|Object} Js2PyTraceDeltasMsg
|
|
237
|
+
* @property {Array.<Object>} trace_deltas
|
|
238
|
+
* Array of trace delta objects. Each trace delta contains the
|
|
239
|
+
* trace's uid along with all of the properties of _fullData that
|
|
240
|
+
* are not identical to those in the FigureModel's _data property
|
|
241
|
+
* @property {Number} trace_edit_id
|
|
242
|
+
* Edit ID of message that triggered the creation of trace deltas
|
|
243
|
+
*/
|
|
244
|
+
_js2py_traceDeltas: null,
|
|
245
|
+
/**
|
|
246
|
+
* Object representing a collection of points for use in click, hover,
|
|
247
|
+
* and selection events
|
|
248
|
+
* @typedef {Object} Points
|
|
249
|
+
* @property {Array.<Number>} trace_indexes
|
|
250
|
+
* Array of the trace index for each point
|
|
251
|
+
* @property {Array.<Number>} point_indexes
|
|
252
|
+
* Array of the index of each point in its own trace
|
|
253
|
+
* @property {null|Array.<Number>} xs
|
|
254
|
+
* Array of the x coordinate of each point (for cartesian trace types)
|
|
255
|
+
* or null (for non-cartesian trace types)
|
|
256
|
+
* @property {null|Array.<Number>} ys
|
|
257
|
+
* Array of the y coordinate of each point (for cartesian trace types)
|
|
258
|
+
* or null (for non-cartesian trace types
|
|
259
|
+
* @property {null|Array.<Number>} zs
|
|
260
|
+
* Array of the z coordinate of each point (for 3D cartesian
|
|
261
|
+
* trace types)
|
|
262
|
+
* or null (for non-3D-cartesian trace types)
|
|
263
|
+
*/
|
|
264
|
+
/**
|
|
265
|
+
* Object representing the state of the input devices during a
|
|
266
|
+
* plotly event
|
|
267
|
+
* @typedef {Object} InputDeviceState
|
|
268
|
+
* @property {boolean} alt - true if alt key pressed,
|
|
269
|
+
* false otherwise
|
|
270
|
+
* @property {boolean} ctrl - true if ctrl key pressed,
|
|
271
|
+
* false otherwise
|
|
272
|
+
* @property {boolean} meta - true if meta key pressed,
|
|
273
|
+
* false otherwise
|
|
274
|
+
* @property {boolean} shift - true if shift key pressed,
|
|
275
|
+
* false otherwise
|
|
276
|
+
*
|
|
277
|
+
* @property {boolean} button
|
|
278
|
+
* Indicates which button was pressed on the mouse to trigger the
|
|
279
|
+
* event.
|
|
280
|
+
* 0: Main button pressed, usually the left button or the
|
|
281
|
+
* un-initialized state
|
|
282
|
+
* 1: Auxiliary button pressed, usually the wheel button or
|
|
283
|
+
* the middle button (if present)
|
|
284
|
+
* 2: Secondary button pressed, usually the right button
|
|
285
|
+
* 3: Fourth button, typically the Browser Back button
|
|
286
|
+
* 4: Fifth button, typically the Browser Forward button
|
|
287
|
+
*
|
|
288
|
+
* @property {boolean} buttons
|
|
289
|
+
* Indicates which buttons were pressed on the mouse when the event
|
|
290
|
+
* is triggered.
|
|
291
|
+
* 0 : No button or un-initialized
|
|
292
|
+
* 1 : Primary button (usually left)
|
|
293
|
+
* 2 : Secondary button (usually right)
|
|
294
|
+
* 4 : Auxilary button (usually middle or mouse wheel button)
|
|
295
|
+
* 8 : 4th button (typically the "Browser Back" button)
|
|
296
|
+
* 16 : 5th button (typically the "Browser Forward" button)
|
|
297
|
+
*
|
|
298
|
+
* Combinations of buttons are represented by the sum of the codes
|
|
299
|
+
* above. e.g. a value of 7 indicates buttons 1 (primary),
|
|
300
|
+
* 2 (secondary), and 4 (auxilary) were pressed during the event
|
|
301
|
+
*/
|
|
302
|
+
/**
|
|
303
|
+
* @typedef {Object} BoxSelectorState
|
|
304
|
+
* @property {Array.<Number>} xrange
|
|
305
|
+
* Two element array containing the x-range of the box selection
|
|
306
|
+
* @property {Array.<Number>} yrange
|
|
307
|
+
* Two element array containing the y-range of the box selection
|
|
308
|
+
*/
|
|
309
|
+
/**
|
|
310
|
+
* @typedef {Object} LassoSelectorState
|
|
311
|
+
* @property {Array.<Number>} xs
|
|
312
|
+
* Array of the x-coordinates of the lasso selection region
|
|
313
|
+
* @property {Array.<Number>} ys
|
|
314
|
+
* Array of the y-coordinates of the lasso selection region
|
|
315
|
+
*/
|
|
316
|
+
/**
|
|
317
|
+
* Object representing the state of the selection tool during a
|
|
318
|
+
* plotly_select event
|
|
319
|
+
* @typedef {Object} Selector
|
|
320
|
+
* @property {String} type
|
|
321
|
+
* Selection type. One of: 'box', or 'lasso'
|
|
322
|
+
* @property {BoxSelectorState|LassoSelectorState} selector_state
|
|
323
|
+
*/
|
|
324
|
+
/**
|
|
325
|
+
* @typedef {null|Object} Js2PyPointsCallbackMsg
|
|
326
|
+
* @property {string} event_type
|
|
327
|
+
* Name of the triggering event. One of 'plotly_click',
|
|
328
|
+
* 'plotly_hover', 'plotly_unhover', or 'plotly_selected'
|
|
329
|
+
* @property {null|Points} points
|
|
330
|
+
* Points object for event
|
|
331
|
+
* @property {null|InputDeviceState} device_state
|
|
332
|
+
* InputDeviceState object for event
|
|
333
|
+
* @property {null|Selector} selector
|
|
334
|
+
* State of the selection tool for 'plotly_selected' events, null
|
|
335
|
+
* for other event types
|
|
336
|
+
*/
|
|
337
|
+
_js2py_pointsCallback: null,
|
|
338
|
+
// Message tracking
|
|
339
|
+
// ----------------
|
|
340
|
+
/**
|
|
341
|
+
* @type {Number}
|
|
342
|
+
* layout_edit_id of the last layout modification operation
|
|
343
|
+
* requested by the Python side
|
|
344
|
+
*/
|
|
345
|
+
_last_layout_edit_id: 0,
|
|
346
|
+
/**
|
|
347
|
+
* @type {Number}
|
|
348
|
+
* trace_edit_id of the last trace modification operation
|
|
349
|
+
* requested by the Python side
|
|
350
|
+
*/
|
|
351
|
+
_last_trace_edit_id: 0 });
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Initialize FigureModel. Called when the Python FigureWidget is first
|
|
355
|
+
* constructed
|
|
356
|
+
*/
|
|
357
|
+
initialize() {
|
|
358
|
+
super.initialize.apply(this, arguments);
|
|
359
|
+
this.on("change:_data", this.do_data, this);
|
|
360
|
+
this.on("change:_layout", this.do_layout, this);
|
|
361
|
+
this.on("change:_py2js_addTraces", this.do_addTraces, this);
|
|
362
|
+
this.on("change:_py2js_deleteTraces", this.do_deleteTraces, this);
|
|
363
|
+
this.on("change:_py2js_moveTraces", this.do_moveTraces, this);
|
|
364
|
+
this.on("change:_py2js_restyle", this.do_restyle, this);
|
|
365
|
+
this.on("change:_py2js_relayout", this.do_relayout, this);
|
|
366
|
+
this.on("change:_py2js_update", this.do_update, this);
|
|
367
|
+
this.on("change:_py2js_animate", this.do_animate, this);
|
|
368
|
+
this.on("change:_py2js_removeLayoutProps", this.do_removeLayoutProps, this);
|
|
369
|
+
this.on("change:_py2js_removeTraceProps", this.do_removeTraceProps, this);
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Input a trace index specification and return an Array of trace
|
|
373
|
+
* indexes where:
|
|
374
|
+
*
|
|
375
|
+
* - null|undefined -> Array of all traces
|
|
376
|
+
* - Trace index as Number -> Single element array of input index
|
|
377
|
+
* - Array of trace indexes -> Input array unchanged
|
|
378
|
+
*
|
|
379
|
+
* @param {undefined|null|Number|Array.<Number>} trace_indexes
|
|
380
|
+
* @returns {Array.<Number>}
|
|
381
|
+
* Array of trace indexes
|
|
382
|
+
* @private
|
|
383
|
+
*/
|
|
384
|
+
_normalize_trace_indexes(trace_indexes) {
|
|
385
|
+
if (trace_indexes === null || trace_indexes === undefined) {
|
|
386
|
+
var numTraces = this.get("_data").length;
|
|
387
|
+
trace_indexes = _.range(numTraces);
|
|
388
|
+
}
|
|
389
|
+
if (!Array.isArray(trace_indexes)) {
|
|
390
|
+
// Make sure idx is an array
|
|
391
|
+
trace_indexes = [trace_indexes];
|
|
392
|
+
}
|
|
393
|
+
return trace_indexes;
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Log changes to the _data trait
|
|
397
|
+
*
|
|
398
|
+
* This should only happed on FigureModel initialization
|
|
399
|
+
*/
|
|
400
|
+
do_data() { }
|
|
401
|
+
/**
|
|
402
|
+
* Log changes to the _layout trait
|
|
403
|
+
*
|
|
404
|
+
* This should only happed on FigureModel initialization
|
|
405
|
+
*/
|
|
406
|
+
do_layout() { }
|
|
407
|
+
/**
|
|
408
|
+
* Handle addTraces message
|
|
409
|
+
*/
|
|
410
|
+
do_addTraces() {
|
|
411
|
+
// add trace to plot
|
|
412
|
+
/** @type {Py2JsAddTracesMsg} */
|
|
413
|
+
var msgData = this.get("_py2js_addTraces");
|
|
414
|
+
if (msgData !== null) {
|
|
415
|
+
var currentTraces = this.get("_data");
|
|
416
|
+
var newTraces = msgData.trace_data;
|
|
417
|
+
_.forEach(newTraces, function (newTrace) {
|
|
418
|
+
currentTraces.push(newTrace);
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Handle deleteTraces message
|
|
424
|
+
*/
|
|
425
|
+
do_deleteTraces() {
|
|
426
|
+
// remove traces from plot
|
|
427
|
+
/** @type {Py2JsDeleteTracesMsg} */
|
|
428
|
+
var msgData = this.get("_py2js_deleteTraces");
|
|
429
|
+
if (msgData !== null) {
|
|
430
|
+
var delete_inds = msgData.delete_inds;
|
|
431
|
+
var tracesData = this.get("_data");
|
|
432
|
+
// Remove del inds in reverse order so indexes remain valid
|
|
433
|
+
// throughout loop
|
|
434
|
+
delete_inds
|
|
435
|
+
.slice()
|
|
436
|
+
.reverse()
|
|
437
|
+
.forEach(function (del_ind) {
|
|
438
|
+
tracesData.splice(del_ind, 1);
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Handle moveTraces message
|
|
444
|
+
*/
|
|
445
|
+
do_moveTraces() {
|
|
446
|
+
/** @type {Py2JsMoveTracesMsg} */
|
|
447
|
+
var msgData = this.get("_py2js_moveTraces");
|
|
448
|
+
if (msgData !== null) {
|
|
449
|
+
var tracesData = this.get("_data");
|
|
450
|
+
var currentInds = msgData.current_trace_inds;
|
|
451
|
+
var newInds = msgData.new_trace_inds;
|
|
452
|
+
performMoveTracesLike(tracesData, currentInds, newInds);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Handle restyle message
|
|
457
|
+
*/
|
|
458
|
+
do_restyle() {
|
|
459
|
+
/** @type {Py2JsRestyleMsg} */
|
|
460
|
+
var msgData = this.get("_py2js_restyle");
|
|
461
|
+
if (msgData !== null) {
|
|
462
|
+
var restyleData = msgData.restyle_data;
|
|
463
|
+
var restyleTraces = this._normalize_trace_indexes(msgData.restyle_traces);
|
|
464
|
+
performRestyleLike(this.get("_data"), restyleData, restyleTraces);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Handle relayout message
|
|
469
|
+
*/
|
|
470
|
+
do_relayout() {
|
|
471
|
+
/** @type {Py2JsRelayoutMsg} */
|
|
472
|
+
var msgData = this.get("_py2js_relayout");
|
|
473
|
+
if (msgData !== null) {
|
|
474
|
+
performRelayoutLike(this.get("_layout"), msgData.relayout_data);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Handle update message
|
|
479
|
+
*/
|
|
480
|
+
do_update() {
|
|
481
|
+
/** @type {Py2JsUpdateMsg} */
|
|
482
|
+
var msgData = this.get("_py2js_update");
|
|
483
|
+
if (msgData !== null) {
|
|
484
|
+
var style = msgData.style_data;
|
|
485
|
+
var layout = msgData.layout_data;
|
|
486
|
+
var styleTraces = this._normalize_trace_indexes(msgData.style_traces);
|
|
487
|
+
performRestyleLike(this.get("_data"), style, styleTraces);
|
|
488
|
+
performRelayoutLike(this.get("_layout"), layout);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Handle animate message
|
|
493
|
+
*/
|
|
494
|
+
do_animate() {
|
|
495
|
+
/** @type {Py2JsAnimateMsg} */
|
|
496
|
+
var msgData = this.get("_py2js_animate");
|
|
497
|
+
if (msgData !== null) {
|
|
498
|
+
var styles = msgData.style_data;
|
|
499
|
+
var layout = msgData.layout_data;
|
|
500
|
+
var trace_indexes = this._normalize_trace_indexes(msgData.style_traces);
|
|
501
|
+
for (var i = 0; i < styles.length; i++) {
|
|
502
|
+
var style = styles[i];
|
|
503
|
+
var trace_index = trace_indexes[i];
|
|
504
|
+
var trace = this.get("_data")[trace_index];
|
|
505
|
+
performRelayoutLike(trace, style);
|
|
506
|
+
}
|
|
507
|
+
performRelayoutLike(this.get("_layout"), layout);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* Handle removeLayoutProps message
|
|
512
|
+
*/
|
|
513
|
+
do_removeLayoutProps() {
|
|
514
|
+
/** @type {Py2JsRemoveLayoutPropsMsg} */
|
|
515
|
+
var msgData = this.get("_py2js_removeLayoutProps");
|
|
516
|
+
if (msgData !== null) {
|
|
517
|
+
var keyPaths = msgData.remove_props;
|
|
518
|
+
var layout = this.get("_layout");
|
|
519
|
+
performRemoveProps(layout, keyPaths);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Handle removeTraceProps message
|
|
524
|
+
*/
|
|
525
|
+
do_removeTraceProps() {
|
|
526
|
+
/** @type {Py2JsRemoveTracePropsMsg} */
|
|
527
|
+
var msgData = this.get("_py2js_removeTraceProps");
|
|
528
|
+
if (msgData !== null) {
|
|
529
|
+
var keyPaths = msgData.remove_props;
|
|
530
|
+
var traceIndex = msgData.remove_trace;
|
|
531
|
+
var trace = this.get("_data")[traceIndex];
|
|
532
|
+
performRemoveProps(trace, keyPaths);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
FigureModel.serializers = Object.assign(Object.assign({}, DOMWidgetModel.serializers), { _data: { deserialize: py2js_deserializer, serialize: js2py_serializer }, _layout: {
|
|
537
|
+
deserialize: py2js_deserializer,
|
|
538
|
+
serialize: js2py_serializer,
|
|
539
|
+
}, _py2js_addTraces: {
|
|
540
|
+
deserialize: py2js_deserializer,
|
|
541
|
+
serialize: js2py_serializer,
|
|
542
|
+
}, _py2js_deleteTraces: {
|
|
543
|
+
deserialize: py2js_deserializer,
|
|
544
|
+
serialize: js2py_serializer,
|
|
545
|
+
}, _py2js_moveTraces: {
|
|
546
|
+
deserialize: py2js_deserializer,
|
|
547
|
+
serialize: js2py_serializer,
|
|
548
|
+
}, _py2js_restyle: {
|
|
549
|
+
deserialize: py2js_deserializer,
|
|
550
|
+
serialize: js2py_serializer,
|
|
551
|
+
}, _py2js_relayout: {
|
|
552
|
+
deserialize: py2js_deserializer,
|
|
553
|
+
serialize: js2py_serializer,
|
|
554
|
+
}, _py2js_update: {
|
|
555
|
+
deserialize: py2js_deserializer,
|
|
556
|
+
serialize: js2py_serializer,
|
|
557
|
+
}, _py2js_animate: {
|
|
558
|
+
deserialize: py2js_deserializer,
|
|
559
|
+
serialize: js2py_serializer,
|
|
560
|
+
}, _py2js_removeLayoutProps: {
|
|
561
|
+
deserialize: py2js_deserializer,
|
|
562
|
+
serialize: js2py_serializer,
|
|
563
|
+
}, _py2js_removeTraceProps: {
|
|
564
|
+
deserialize: py2js_deserializer,
|
|
565
|
+
serialize: js2py_serializer,
|
|
566
|
+
}, _js2py_restyle: {
|
|
567
|
+
deserialize: py2js_deserializer,
|
|
568
|
+
serialize: js2py_serializer,
|
|
569
|
+
}, _js2py_relayout: {
|
|
570
|
+
deserialize: py2js_deserializer,
|
|
571
|
+
serialize: js2py_serializer,
|
|
572
|
+
}, _js2py_update: {
|
|
573
|
+
deserialize: py2js_deserializer,
|
|
574
|
+
serialize: js2py_serializer,
|
|
575
|
+
}, _js2py_layoutDelta: {
|
|
576
|
+
deserialize: py2js_deserializer,
|
|
577
|
+
serialize: js2py_serializer,
|
|
578
|
+
}, _js2py_traceDeltas: {
|
|
579
|
+
deserialize: py2js_deserializer,
|
|
580
|
+
serialize: js2py_serializer,
|
|
581
|
+
}, _js2py_pointsCallback: {
|
|
582
|
+
deserialize: py2js_deserializer,
|
|
583
|
+
serialize: js2py_serializer,
|
|
584
|
+
} });
|
|
585
|
+
FigureModel.model_name = "FigureModel";
|
|
586
|
+
FigureModel.model_module = MODULE_NAME;
|
|
587
|
+
FigureModel.model_module_version = semver_range;
|
|
588
|
+
FigureModel.view_name = "FigureView";
|
|
589
|
+
FigureModel.view_module = MODULE_NAME;
|
|
590
|
+
FigureModel.view_module_version = semver_range;
|
|
591
|
+
// View
|
|
592
|
+
// ====
|
|
593
|
+
/**
|
|
594
|
+
* A FigureView manages the visual presentation of a single Plotly.js
|
|
595
|
+
* figure for a single notebook output cell. Each FigureView has a
|
|
596
|
+
* reference to FigureModel. Multiple views may share a single model
|
|
597
|
+
* instance, as is the case when a Python FigureWidget is displayed in
|
|
598
|
+
* multiple notebook output cells.
|
|
599
|
+
*
|
|
600
|
+
* @type {widgets.DOMWidgetView}
|
|
601
|
+
*/
|
|
602
|
+
export class FigureView extends DOMWidgetView {
|
|
603
|
+
/**
|
|
604
|
+
* The perform_render method is called by processLuminoMessage
|
|
605
|
+
* after the widget's DOM element has been attached to the notebook
|
|
606
|
+
* output cell. This happens after the initialize of the
|
|
607
|
+
* FigureModel, and it won't happen at all if the Python FigureWidget
|
|
608
|
+
* is never displayed in a notebook output cell
|
|
609
|
+
*/
|
|
610
|
+
perform_render() {
|
|
611
|
+
var that = this;
|
|
612
|
+
// Wire up message property callbacks
|
|
613
|
+
// ----------------------------------
|
|
614
|
+
// Python -> JS event properties
|
|
615
|
+
this.model.on("change:_py2js_addTraces", this.do_addTraces, this);
|
|
616
|
+
this.model.on("change:_py2js_deleteTraces", this.do_deleteTraces, this);
|
|
617
|
+
this.model.on("change:_py2js_moveTraces", this.do_moveTraces, this);
|
|
618
|
+
this.model.on("change:_py2js_restyle", this.do_restyle, this);
|
|
619
|
+
this.model.on("change:_py2js_relayout", this.do_relayout, this);
|
|
620
|
+
this.model.on("change:_py2js_update", this.do_update, this);
|
|
621
|
+
this.model.on("change:_py2js_animate", this.do_animate, this);
|
|
622
|
+
// MathJax configuration
|
|
623
|
+
// ---------------------
|
|
624
|
+
if (window.MathJax) {
|
|
625
|
+
window.MathJax.Hub.Config({ SVG: { font: "STIX-Web" } });
|
|
626
|
+
}
|
|
627
|
+
// Get message ids
|
|
628
|
+
// ---------------------
|
|
629
|
+
var layout_edit_id = this.model.get("_last_layout_edit_id");
|
|
630
|
+
var trace_edit_id = this.model.get("_last_trace_edit_id");
|
|
631
|
+
// Set view UID
|
|
632
|
+
// ------------
|
|
633
|
+
this.viewID = randstr();
|
|
634
|
+
// Initialize Plotly.js figure
|
|
635
|
+
// ---------------------------
|
|
636
|
+
// We must clone the model's data and layout properties so that
|
|
637
|
+
// the model is not directly mutated by the Plotly.js library.
|
|
638
|
+
var initialTraces = _.cloneDeep(this.model.get("_data"));
|
|
639
|
+
var initialLayout = _.cloneDeep(this.model.get("_layout"));
|
|
640
|
+
var config = this.model.get("_config");
|
|
641
|
+
Plotly.newPlot(that.el, initialTraces, initialLayout, config).then(function () {
|
|
642
|
+
// ### Send trace deltas ###
|
|
643
|
+
// We create an array of deltas corresponding to the new
|
|
644
|
+
// traces.
|
|
645
|
+
that._sendTraceDeltas(trace_edit_id);
|
|
646
|
+
// ### Send layout delta ###
|
|
647
|
+
that._sendLayoutDelta(layout_edit_id);
|
|
648
|
+
// Wire up plotly event callbacks
|
|
649
|
+
that.el.on("plotly_restyle", function (update) {
|
|
650
|
+
that.handle_plotly_restyle(update);
|
|
651
|
+
});
|
|
652
|
+
that.el.on("plotly_relayout", function (update) {
|
|
653
|
+
that.handle_plotly_relayout(update);
|
|
654
|
+
});
|
|
655
|
+
/*
|
|
656
|
+
(<Plotly.PlotlyHTMLElement>that.el).on("plotly_update", function (update: any) {
|
|
657
|
+
that.handle_plotly_update(update);
|
|
658
|
+
});
|
|
659
|
+
*/
|
|
660
|
+
that.el.on("plotly_click", function (update) {
|
|
661
|
+
that.handle_plotly_click(update);
|
|
662
|
+
});
|
|
663
|
+
that.el.on("plotly_hover", function (update) {
|
|
664
|
+
that.handle_plotly_hover(update);
|
|
665
|
+
});
|
|
666
|
+
that.el.on("plotly_unhover", function (update) {
|
|
667
|
+
that.handle_plotly_unhover(update);
|
|
668
|
+
});
|
|
669
|
+
that.el.on("plotly_selected", function (update) {
|
|
670
|
+
that.handle_plotly_selected(update);
|
|
671
|
+
});
|
|
672
|
+
/*
|
|
673
|
+
(<Plotly.PlotlyHTMLElement>that.el).on("plotly_deselect", function (update: any) {
|
|
674
|
+
that.handle_plotly_deselect(update);
|
|
675
|
+
});
|
|
676
|
+
(<Plotly.PlotlyHTMLElement>that.el).on("plotly_doubleclick", function (update: any) {
|
|
677
|
+
that.handle_plotly_doubleclick(update);
|
|
678
|
+
});
|
|
679
|
+
*/
|
|
680
|
+
// Emit event indicating that the widget has finished
|
|
681
|
+
// rendering
|
|
682
|
+
var event = new CustomEvent("plotlywidget-after-render", {
|
|
683
|
+
detail: { element: that.el, viewID: that.viewID },
|
|
684
|
+
});
|
|
685
|
+
// Dispatch/Trigger/Fire the event
|
|
686
|
+
document.dispatchEvent(event);
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* Respond to phosphorjs events
|
|
691
|
+
*/
|
|
692
|
+
processLuminoMessage(msg) {
|
|
693
|
+
super.processLuminoMessage.apply(this, arguments);
|
|
694
|
+
var that = this;
|
|
695
|
+
switch (msg.type) {
|
|
696
|
+
case "before-attach":
|
|
697
|
+
// Render an initial empty figure. This establishes with
|
|
698
|
+
// the page that the element will not be empty, avoiding
|
|
699
|
+
// some occasions where the dynamic sizing behavior leads
|
|
700
|
+
// to collapsed figure dimensions.
|
|
701
|
+
var axisHidden = {
|
|
702
|
+
showgrid: false,
|
|
703
|
+
showline: false,
|
|
704
|
+
tickvals: [],
|
|
705
|
+
};
|
|
706
|
+
Plotly.newPlot(that.el, [], {
|
|
707
|
+
xaxis: axisHidden,
|
|
708
|
+
yaxis: axisHidden,
|
|
709
|
+
});
|
|
710
|
+
window.addEventListener("resize", function () {
|
|
711
|
+
that.autosizeFigure();
|
|
712
|
+
});
|
|
713
|
+
break;
|
|
714
|
+
case "after-attach":
|
|
715
|
+
// Rendering actual figure in the after-attach event allows
|
|
716
|
+
// Plotly.js to size the figure to fill the available element
|
|
717
|
+
this.perform_render();
|
|
718
|
+
break;
|
|
719
|
+
case "resize":
|
|
720
|
+
this.autosizeFigure();
|
|
721
|
+
break;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
autosizeFigure() {
|
|
725
|
+
var that = this;
|
|
726
|
+
var layout = that.model.get("_layout");
|
|
727
|
+
if (_.isNil(layout) || _.isNil(layout.width)) {
|
|
728
|
+
// @ts-ignore
|
|
729
|
+
Plotly.Plots.resize(that.el).then(function () {
|
|
730
|
+
var layout_edit_id = that.model.get("_last_layout_edit_id");
|
|
731
|
+
that._sendLayoutDelta(layout_edit_id);
|
|
732
|
+
});
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
/**
|
|
736
|
+
* Purge Plotly.js data structures from the notebook output display
|
|
737
|
+
* element when the view is destroyed
|
|
738
|
+
*/
|
|
739
|
+
destroy() {
|
|
740
|
+
Plotly.purge(this.el);
|
|
741
|
+
}
|
|
742
|
+
/**
|
|
743
|
+
* Return the figure's _fullData array merged with its data array
|
|
744
|
+
*
|
|
745
|
+
* The merge ensures that for any properties that el._fullData and
|
|
746
|
+
* el.data have in common, we return the version from el.data
|
|
747
|
+
*
|
|
748
|
+
* Named colorscales are one example of why this is needed. The el.data
|
|
749
|
+
* array will hold named colorscale strings (e.g. 'Viridis'), while the
|
|
750
|
+
* el._fullData array will hold the actual colorscale array. e.g.
|
|
751
|
+
*
|
|
752
|
+
* el.data[0].marker.colorscale == 'Viridis' but
|
|
753
|
+
* el._fullData[0].marker.colorscale = [[..., ...], ...]
|
|
754
|
+
*
|
|
755
|
+
* Performing the merge allows our FigureModel to retain the 'Viridis'
|
|
756
|
+
* string, rather than having it overridded by the colorscale array.
|
|
757
|
+
*
|
|
758
|
+
*/
|
|
759
|
+
getFullData() {
|
|
760
|
+
return _.mergeWith({}, this.el._fullData, this.el.data, fullMergeCustomizer);
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* Return the figure's _fullLayout object merged with its layout object
|
|
764
|
+
*
|
|
765
|
+
* See getFullData documentation for discussion of why the merge is
|
|
766
|
+
* necessary
|
|
767
|
+
*/
|
|
768
|
+
getFullLayout() {
|
|
769
|
+
return _.mergeWith({}, this.el._fullLayout, this.el.layout, fullMergeCustomizer);
|
|
770
|
+
}
|
|
771
|
+
/**
|
|
772
|
+
* Build Points data structure from data supplied by the plotly_click,
|
|
773
|
+
* plotly_hover, or plotly_select events
|
|
774
|
+
* @param {Object} data
|
|
775
|
+
* @returns {null|Points}
|
|
776
|
+
*/
|
|
777
|
+
buildPointsObject(data) {
|
|
778
|
+
var pointsObject;
|
|
779
|
+
if (data.hasOwnProperty("points")) {
|
|
780
|
+
// Most cartesian plots
|
|
781
|
+
var pointObjects = data["points"];
|
|
782
|
+
var numPoints = pointObjects.length;
|
|
783
|
+
var hasNestedPointObjects = true;
|
|
784
|
+
for (let i = 0; i < numPoints; i++) {
|
|
785
|
+
hasNestedPointObjects =
|
|
786
|
+
hasNestedPointObjects &&
|
|
787
|
+
pointObjects[i].hasOwnProperty("pointNumbers");
|
|
788
|
+
if (!hasNestedPointObjects)
|
|
789
|
+
break;
|
|
790
|
+
}
|
|
791
|
+
var numPointNumbers = numPoints;
|
|
792
|
+
if (hasNestedPointObjects) {
|
|
793
|
+
numPointNumbers = 0;
|
|
794
|
+
for (let i = 0; i < numPoints; i++) {
|
|
795
|
+
numPointNumbers += pointObjects[i]["pointNumbers"].length;
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
pointsObject = {
|
|
799
|
+
trace_indexes: new Array(numPointNumbers),
|
|
800
|
+
point_indexes: new Array(numPointNumbers),
|
|
801
|
+
xs: new Array(numPointNumbers),
|
|
802
|
+
ys: new Array(numPointNumbers),
|
|
803
|
+
};
|
|
804
|
+
if (hasNestedPointObjects) {
|
|
805
|
+
var flatPointIndex = 0;
|
|
806
|
+
for (var p = 0; p < numPoints; p++) {
|
|
807
|
+
for (let i = 0; i < pointObjects[p]["pointNumbers"].length; i++, flatPointIndex++) {
|
|
808
|
+
pointsObject["point_indexes"][flatPointIndex] =
|
|
809
|
+
pointObjects[p]["pointNumbers"][i];
|
|
810
|
+
// also add xs, ys and traces so that the array doesn't get truncated later
|
|
811
|
+
pointsObject["xs"][flatPointIndex] = pointObjects[p]["x"];
|
|
812
|
+
pointsObject["ys"][flatPointIndex] = pointObjects[p]["y"];
|
|
813
|
+
pointsObject["trace_indexes"][flatPointIndex] =
|
|
814
|
+
pointObjects[p]["curveNumber"];
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
let single_trace = true;
|
|
818
|
+
for (let i = 1; i < numPointNumbers; i++) {
|
|
819
|
+
single_trace = single_trace && (pointsObject["trace_indexes"][i - 1] === pointsObject["trace_indexes"][i]);
|
|
820
|
+
if (!single_trace)
|
|
821
|
+
break;
|
|
822
|
+
}
|
|
823
|
+
if (single_trace) {
|
|
824
|
+
pointsObject["point_indexes"].sort((function (a, b) {
|
|
825
|
+
return a - b;
|
|
826
|
+
}));
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
else {
|
|
830
|
+
for (var p = 0; p < numPoints; p++) {
|
|
831
|
+
pointsObject["trace_indexes"][p] = pointObjects[p]["curveNumber"];
|
|
832
|
+
pointsObject["point_indexes"][p] = pointObjects[p]["pointNumber"];
|
|
833
|
+
pointsObject["xs"][p] = pointObjects[p]["x"];
|
|
834
|
+
pointsObject["ys"][p] = pointObjects[p]["y"];
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
// Add z if present
|
|
838
|
+
var hasZ = pointObjects[0] !== undefined && pointObjects[0].hasOwnProperty("z");
|
|
839
|
+
if (hasZ) {
|
|
840
|
+
pointsObject["zs"] = new Array(numPoints);
|
|
841
|
+
for (p = 0; p < numPoints; p++) {
|
|
842
|
+
pointsObject["zs"][p] = pointObjects[p]["z"];
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
return pointsObject;
|
|
846
|
+
}
|
|
847
|
+
else {
|
|
848
|
+
return null;
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
/**
|
|
852
|
+
* Build InputDeviceState data structure from data supplied by the
|
|
853
|
+
* plotly_click, plotly_hover, or plotly_select events
|
|
854
|
+
* @param {Object} data
|
|
855
|
+
* @returns {null|InputDeviceState}
|
|
856
|
+
*/
|
|
857
|
+
buildInputDeviceStateObject(data) {
|
|
858
|
+
var event = data["event"];
|
|
859
|
+
if (event === undefined) {
|
|
860
|
+
return null;
|
|
861
|
+
}
|
|
862
|
+
else {
|
|
863
|
+
/** @type {InputDeviceState} */
|
|
864
|
+
var inputDeviceState = {
|
|
865
|
+
// Keyboard modifiers
|
|
866
|
+
alt: event["altKey"],
|
|
867
|
+
ctrl: event["ctrlKey"],
|
|
868
|
+
meta: event["metaKey"],
|
|
869
|
+
shift: event["shiftKey"],
|
|
870
|
+
// Mouse buttons
|
|
871
|
+
button: event["button"],
|
|
872
|
+
buttons: event["buttons"],
|
|
873
|
+
};
|
|
874
|
+
return inputDeviceState;
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
/**
|
|
878
|
+
* Build Selector data structure from data supplied by the
|
|
879
|
+
* plotly_select event
|
|
880
|
+
* @param data
|
|
881
|
+
* @returns {null|Selector}
|
|
882
|
+
*/
|
|
883
|
+
buildSelectorObject(data) {
|
|
884
|
+
var selectorObject;
|
|
885
|
+
if (data.hasOwnProperty("range")) {
|
|
886
|
+
// Box selection
|
|
887
|
+
selectorObject = {
|
|
888
|
+
type: "box",
|
|
889
|
+
selector_state: {
|
|
890
|
+
xrange: data["range"]["x"],
|
|
891
|
+
yrange: data["range"]["y"],
|
|
892
|
+
},
|
|
893
|
+
};
|
|
894
|
+
}
|
|
895
|
+
else if (data.hasOwnProperty("lassoPoints")) {
|
|
896
|
+
// Lasso selection
|
|
897
|
+
selectorObject = {
|
|
898
|
+
type: "lasso",
|
|
899
|
+
selector_state: {
|
|
900
|
+
xs: data["lassoPoints"]["x"],
|
|
901
|
+
ys: data["lassoPoints"]["y"],
|
|
902
|
+
},
|
|
903
|
+
};
|
|
904
|
+
}
|
|
905
|
+
else {
|
|
906
|
+
selectorObject = null;
|
|
907
|
+
}
|
|
908
|
+
return selectorObject;
|
|
909
|
+
}
|
|
910
|
+
/**
|
|
911
|
+
* Handle ploty_restyle events emitted by the Plotly.js library
|
|
912
|
+
* @param data
|
|
913
|
+
*/
|
|
914
|
+
handle_plotly_restyle(data) {
|
|
915
|
+
if (data === null || data === undefined) {
|
|
916
|
+
// No data to report to the Python side
|
|
917
|
+
return;
|
|
918
|
+
}
|
|
919
|
+
if (data[0] && data[0].hasOwnProperty("_doNotReportToPy")) {
|
|
920
|
+
// Restyle originated on the Python side
|
|
921
|
+
return;
|
|
922
|
+
}
|
|
923
|
+
// Unpack data
|
|
924
|
+
var styleData = data[0];
|
|
925
|
+
var styleTraces = data[1];
|
|
926
|
+
// Construct restyle message to send to the Python side
|
|
927
|
+
/** @type {Js2PyRestyleMsg} */
|
|
928
|
+
var restyleMsg = {
|
|
929
|
+
style_data: styleData,
|
|
930
|
+
style_traces: styleTraces,
|
|
931
|
+
source_view_id: this.viewID,
|
|
932
|
+
};
|
|
933
|
+
this.model.set("_js2py_restyle", restyleMsg);
|
|
934
|
+
this.touch();
|
|
935
|
+
}
|
|
936
|
+
/**
|
|
937
|
+
* Handle plotly_relayout events emitted by the Plotly.js library
|
|
938
|
+
* @param data
|
|
939
|
+
*/
|
|
940
|
+
handle_plotly_relayout(data) {
|
|
941
|
+
if (data === null || data === undefined) {
|
|
942
|
+
// No data to report to the Python side
|
|
943
|
+
return;
|
|
944
|
+
}
|
|
945
|
+
if (data.hasOwnProperty("_doNotReportToPy")) {
|
|
946
|
+
// Relayout originated on the Python side
|
|
947
|
+
return;
|
|
948
|
+
}
|
|
949
|
+
/** @type {Js2PyRelayoutMsg} */
|
|
950
|
+
var relayoutMsg = {
|
|
951
|
+
relayout_data: data,
|
|
952
|
+
source_view_id: this.viewID,
|
|
953
|
+
};
|
|
954
|
+
this.model.set("_js2py_relayout", relayoutMsg);
|
|
955
|
+
this.touch();
|
|
956
|
+
}
|
|
957
|
+
/**
|
|
958
|
+
* Handle plotly_update events emitted by the Plotly.js library
|
|
959
|
+
* @param data
|
|
960
|
+
*/
|
|
961
|
+
handle_plotly_update(data) {
|
|
962
|
+
if (data === null || data === undefined) {
|
|
963
|
+
// No data to report to the Python side
|
|
964
|
+
return;
|
|
965
|
+
}
|
|
966
|
+
if (data["data"] && data["data"][0].hasOwnProperty("_doNotReportToPy")) {
|
|
967
|
+
// Update originated on the Python side
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
970
|
+
/** @type {Js2PyUpdateMsg} */
|
|
971
|
+
var updateMsg = {
|
|
972
|
+
style_data: data["data"][0],
|
|
973
|
+
style_traces: data["data"][1],
|
|
974
|
+
layout_data: data["layout"],
|
|
975
|
+
source_view_id: this.viewID,
|
|
976
|
+
};
|
|
977
|
+
// Log message
|
|
978
|
+
this.model.set("_js2py_update", updateMsg);
|
|
979
|
+
this.touch();
|
|
980
|
+
}
|
|
981
|
+
/**
|
|
982
|
+
* Handle plotly_click events emitted by the Plotly.js library
|
|
983
|
+
* @param data
|
|
984
|
+
*/
|
|
985
|
+
handle_plotly_click(data) {
|
|
986
|
+
this._send_points_callback_message(data, "plotly_click");
|
|
987
|
+
}
|
|
988
|
+
/**
|
|
989
|
+
* Handle plotly_hover events emitted by the Plotly.js library
|
|
990
|
+
* @param data
|
|
991
|
+
*/
|
|
992
|
+
handle_plotly_hover(data) {
|
|
993
|
+
this._send_points_callback_message(data, "plotly_hover");
|
|
994
|
+
}
|
|
995
|
+
/**
|
|
996
|
+
* Handle plotly_unhover events emitted by the Plotly.js library
|
|
997
|
+
* @param data
|
|
998
|
+
*/
|
|
999
|
+
handle_plotly_unhover(data) {
|
|
1000
|
+
this._send_points_callback_message(data, "plotly_unhover");
|
|
1001
|
+
}
|
|
1002
|
+
/**
|
|
1003
|
+
* Handle plotly_selected events emitted by the Plotly.js library
|
|
1004
|
+
* @param data
|
|
1005
|
+
*/
|
|
1006
|
+
handle_plotly_selected(data) {
|
|
1007
|
+
this._send_points_callback_message(data, "plotly_selected");
|
|
1008
|
+
}
|
|
1009
|
+
/**
|
|
1010
|
+
* Handle plotly_deselect events emitted by the Plotly.js library
|
|
1011
|
+
* @param data
|
|
1012
|
+
*/
|
|
1013
|
+
handle_plotly_deselect(data) {
|
|
1014
|
+
data = {
|
|
1015
|
+
points: [],
|
|
1016
|
+
};
|
|
1017
|
+
this._send_points_callback_message(data, "plotly_deselect");
|
|
1018
|
+
}
|
|
1019
|
+
/**
|
|
1020
|
+
* Build and send a points callback message to the Python side
|
|
1021
|
+
*
|
|
1022
|
+
* @param {Object} data
|
|
1023
|
+
* data object as provided by the plotly_click, plotly_hover,
|
|
1024
|
+
* plotly_unhover, or plotly_selected events
|
|
1025
|
+
* @param {String} event_type
|
|
1026
|
+
* Name of the triggering event. One of 'plotly_click',
|
|
1027
|
+
* 'plotly_hover', 'plotly_unhover', or 'plotly_selected'
|
|
1028
|
+
* @private
|
|
1029
|
+
*/
|
|
1030
|
+
_send_points_callback_message(data, event_type) {
|
|
1031
|
+
if (data === null || data === undefined) {
|
|
1032
|
+
// No data to report to the Python side
|
|
1033
|
+
return;
|
|
1034
|
+
}
|
|
1035
|
+
/** @type {Js2PyPointsCallbackMsg} */
|
|
1036
|
+
var pointsMsg = {
|
|
1037
|
+
event_type: event_type,
|
|
1038
|
+
points: this.buildPointsObject(data),
|
|
1039
|
+
device_state: this.buildInputDeviceStateObject(data),
|
|
1040
|
+
selector: this.buildSelectorObject(data),
|
|
1041
|
+
};
|
|
1042
|
+
if (pointsMsg["points"] !== null && pointsMsg["points"] !== undefined) {
|
|
1043
|
+
this.model.set("_js2py_pointsCallback", pointsMsg);
|
|
1044
|
+
this.touch();
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
/**
|
|
1048
|
+
* Stub for future handling of plotly_doubleclick
|
|
1049
|
+
* @param data
|
|
1050
|
+
*/
|
|
1051
|
+
handle_plotly_doubleclick(data) { }
|
|
1052
|
+
/**
|
|
1053
|
+
* Handle Plotly.addTraces request
|
|
1054
|
+
*/
|
|
1055
|
+
do_addTraces() {
|
|
1056
|
+
/** @type {Py2JsAddTracesMsg} */
|
|
1057
|
+
var msgData = this.model.get("_py2js_addTraces");
|
|
1058
|
+
if (msgData !== null) {
|
|
1059
|
+
var that = this;
|
|
1060
|
+
Plotly.addTraces(this.el, msgData.trace_data).then(function () {
|
|
1061
|
+
// ### Send trace deltas ###
|
|
1062
|
+
that._sendTraceDeltas(msgData.trace_edit_id);
|
|
1063
|
+
// ### Send layout delta ###
|
|
1064
|
+
var layout_edit_id = msgData.layout_edit_id;
|
|
1065
|
+
that._sendLayoutDelta(layout_edit_id);
|
|
1066
|
+
});
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
/**
|
|
1070
|
+
* Handle Plotly.deleteTraces request
|
|
1071
|
+
*/
|
|
1072
|
+
do_deleteTraces() {
|
|
1073
|
+
/** @type {Py2JsDeleteTracesMsg} */
|
|
1074
|
+
var msgData = this.model.get("_py2js_deleteTraces");
|
|
1075
|
+
if (msgData !== null) {
|
|
1076
|
+
var delete_inds = msgData.delete_inds;
|
|
1077
|
+
var that = this;
|
|
1078
|
+
Plotly.deleteTraces(this.el, delete_inds).then(function () {
|
|
1079
|
+
// ### Send trace deltas ###
|
|
1080
|
+
var trace_edit_id = msgData.trace_edit_id;
|
|
1081
|
+
that._sendTraceDeltas(trace_edit_id);
|
|
1082
|
+
// ### Send layout delta ###
|
|
1083
|
+
var layout_edit_id = msgData.layout_edit_id;
|
|
1084
|
+
that._sendLayoutDelta(layout_edit_id);
|
|
1085
|
+
});
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
/**
|
|
1089
|
+
* Handle Plotly.moveTraces request
|
|
1090
|
+
*/
|
|
1091
|
+
do_moveTraces() {
|
|
1092
|
+
/** @type {Py2JsMoveTracesMsg} */
|
|
1093
|
+
var msgData = this.model.get("_py2js_moveTraces");
|
|
1094
|
+
if (msgData !== null) {
|
|
1095
|
+
// Unpack message
|
|
1096
|
+
var currentInds = msgData.current_trace_inds;
|
|
1097
|
+
var newInds = msgData.new_trace_inds;
|
|
1098
|
+
// Check if the new trace indexes are actually different than
|
|
1099
|
+
// the current indexes
|
|
1100
|
+
var inds_equal = _.isEqual(currentInds, newInds);
|
|
1101
|
+
if (!inds_equal) {
|
|
1102
|
+
Plotly.moveTraces(this.el, currentInds, newInds);
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
/**
|
|
1107
|
+
* Handle Plotly.restyle request
|
|
1108
|
+
*/
|
|
1109
|
+
do_restyle() {
|
|
1110
|
+
/** @type {Py2JsRestyleMsg} */
|
|
1111
|
+
var msgData = this.model.get("_py2js_restyle");
|
|
1112
|
+
if (msgData !== null) {
|
|
1113
|
+
var restyleData = msgData.restyle_data;
|
|
1114
|
+
var traceIndexes = this.model._normalize_trace_indexes(msgData.restyle_traces);
|
|
1115
|
+
restyleData["_doNotReportToPy"] = true;
|
|
1116
|
+
Plotly.restyle(this.el, restyleData, traceIndexes);
|
|
1117
|
+
// ### Send trace deltas ###
|
|
1118
|
+
// We create an array of deltas corresponding to the restyled
|
|
1119
|
+
// traces.
|
|
1120
|
+
this._sendTraceDeltas(msgData.trace_edit_id);
|
|
1121
|
+
// ### Send layout delta ###
|
|
1122
|
+
var layout_edit_id = msgData.layout_edit_id;
|
|
1123
|
+
this._sendLayoutDelta(layout_edit_id);
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
/**
|
|
1127
|
+
* Handle Plotly.relayout request
|
|
1128
|
+
*/
|
|
1129
|
+
do_relayout() {
|
|
1130
|
+
/** @type {Py2JsRelayoutMsg} */
|
|
1131
|
+
var msgData = this.model.get("_py2js_relayout");
|
|
1132
|
+
if (msgData !== null) {
|
|
1133
|
+
if (msgData.source_view_id !== this.viewID) {
|
|
1134
|
+
var relayoutData = msgData.relayout_data;
|
|
1135
|
+
relayoutData["_doNotReportToPy"] = true;
|
|
1136
|
+
Plotly.relayout(this.el, msgData.relayout_data);
|
|
1137
|
+
}
|
|
1138
|
+
// ### Send layout delta ###
|
|
1139
|
+
var layout_edit_id = msgData.layout_edit_id;
|
|
1140
|
+
this._sendLayoutDelta(layout_edit_id);
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
/**
|
|
1144
|
+
* Handle Plotly.update request
|
|
1145
|
+
*/
|
|
1146
|
+
do_update() {
|
|
1147
|
+
/** @type {Py2JsUpdateMsg} */
|
|
1148
|
+
var msgData = this.model.get("_py2js_update");
|
|
1149
|
+
if (msgData !== null) {
|
|
1150
|
+
var style = msgData.style_data || {};
|
|
1151
|
+
var layout = msgData.layout_data || {};
|
|
1152
|
+
var traceIndexes = this.model._normalize_trace_indexes(msgData.style_traces);
|
|
1153
|
+
style["_doNotReportToPy"] = true;
|
|
1154
|
+
Plotly.update(this.el, style, layout, traceIndexes);
|
|
1155
|
+
// ### Send trace deltas ###
|
|
1156
|
+
// We create an array of deltas corresponding to the updated
|
|
1157
|
+
// traces.
|
|
1158
|
+
this._sendTraceDeltas(msgData.trace_edit_id);
|
|
1159
|
+
// ### Send layout delta ###
|
|
1160
|
+
var layout_edit_id = msgData.layout_edit_id;
|
|
1161
|
+
this._sendLayoutDelta(layout_edit_id);
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
/**
|
|
1165
|
+
* Handle Plotly.animate request
|
|
1166
|
+
*/
|
|
1167
|
+
do_animate() {
|
|
1168
|
+
/** @type {Py2JsAnimateMsg} */
|
|
1169
|
+
var msgData = this.model.get("_py2js_animate");
|
|
1170
|
+
if (msgData !== null) {
|
|
1171
|
+
// Unpack params
|
|
1172
|
+
// var animationData = msgData[0];
|
|
1173
|
+
var animationOpts = msgData.animation_opts;
|
|
1174
|
+
var styles = msgData.style_data;
|
|
1175
|
+
var layout = msgData.layout_data;
|
|
1176
|
+
var traceIndexes = this.model._normalize_trace_indexes(msgData.style_traces);
|
|
1177
|
+
var animationData = {
|
|
1178
|
+
data: styles,
|
|
1179
|
+
layout: layout,
|
|
1180
|
+
traces: traceIndexes,
|
|
1181
|
+
};
|
|
1182
|
+
animationData["_doNotReportToPy"] = true;
|
|
1183
|
+
var that = this;
|
|
1184
|
+
// @ts-ignore
|
|
1185
|
+
Plotly.animate(this.el, animationData, animationOpts).then(function () {
|
|
1186
|
+
// ### Send trace deltas ###
|
|
1187
|
+
// We create an array of deltas corresponding to the
|
|
1188
|
+
// animated traces.
|
|
1189
|
+
that._sendTraceDeltas(msgData.trace_edit_id);
|
|
1190
|
+
// ### Send layout delta ###
|
|
1191
|
+
var layout_edit_id = msgData.layout_edit_id;
|
|
1192
|
+
that._sendLayoutDelta(layout_edit_id);
|
|
1193
|
+
});
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
/**
|
|
1197
|
+
* Construct layout delta object and send layoutDelta message to the
|
|
1198
|
+
* Python side
|
|
1199
|
+
*
|
|
1200
|
+
* @param layout_edit_id
|
|
1201
|
+
* Edit ID of message that triggered the creation of the layout delta
|
|
1202
|
+
* @private
|
|
1203
|
+
*/
|
|
1204
|
+
_sendLayoutDelta(layout_edit_id) {
|
|
1205
|
+
// ### Handle layout delta ###
|
|
1206
|
+
var layout_delta = createDeltaObject(this.getFullLayout(), this.model.get("_layout"));
|
|
1207
|
+
/** @type{Js2PyLayoutDeltaMsg} */
|
|
1208
|
+
var layoutDeltaMsg = {
|
|
1209
|
+
layout_delta: layout_delta,
|
|
1210
|
+
layout_edit_id: layout_edit_id,
|
|
1211
|
+
};
|
|
1212
|
+
this.model.set("_js2py_layoutDelta", layoutDeltaMsg);
|
|
1213
|
+
this.touch();
|
|
1214
|
+
}
|
|
1215
|
+
/**
|
|
1216
|
+
* Construct trace deltas array for the requested trace indexes and
|
|
1217
|
+
* send traceDeltas message to the Python side
|
|
1218
|
+
* Array of indexes of traces for which to compute deltas
|
|
1219
|
+
* @param trace_edit_id
|
|
1220
|
+
* Edit ID of message that triggered the creation of trace deltas
|
|
1221
|
+
* @private
|
|
1222
|
+
*/
|
|
1223
|
+
_sendTraceDeltas(trace_edit_id) {
|
|
1224
|
+
var trace_data = this.model.get("_data");
|
|
1225
|
+
var traceIndexes = _.range(trace_data.length);
|
|
1226
|
+
var trace_deltas = new Array(traceIndexes.length);
|
|
1227
|
+
var fullData = this.getFullData();
|
|
1228
|
+
for (var i = 0; i < traceIndexes.length; i++) {
|
|
1229
|
+
var traceInd = traceIndexes[i];
|
|
1230
|
+
trace_deltas[i] = createDeltaObject(fullData[traceInd], trace_data[traceInd]);
|
|
1231
|
+
}
|
|
1232
|
+
/** @type{Js2PyTraceDeltasMsg} */
|
|
1233
|
+
var traceDeltasMsg = {
|
|
1234
|
+
trace_deltas: trace_deltas,
|
|
1235
|
+
trace_edit_id: trace_edit_id,
|
|
1236
|
+
};
|
|
1237
|
+
this.model.set("_js2py_traceDeltas", traceDeltasMsg);
|
|
1238
|
+
this.touch();
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
// Serialization
|
|
1242
|
+
/**
|
|
1243
|
+
* Create a mapping from numpy dtype strings to corresponding typed array
|
|
1244
|
+
* constructors
|
|
1245
|
+
*/
|
|
1246
|
+
const numpy_dtype_to_typedarray_type = {
|
|
1247
|
+
int8: Int8Array,
|
|
1248
|
+
int16: Int16Array,
|
|
1249
|
+
int32: Int32Array,
|
|
1250
|
+
uint8: Uint8Array,
|
|
1251
|
+
uint16: Uint16Array,
|
|
1252
|
+
uint32: Uint32Array,
|
|
1253
|
+
float32: Float32Array,
|
|
1254
|
+
float64: Float64Array,
|
|
1255
|
+
};
|
|
1256
|
+
function serializeTypedArray(v) {
|
|
1257
|
+
var numpyType;
|
|
1258
|
+
if (v instanceof Int8Array) {
|
|
1259
|
+
numpyType = "int8";
|
|
1260
|
+
}
|
|
1261
|
+
else if (v instanceof Int16Array) {
|
|
1262
|
+
numpyType = "int16";
|
|
1263
|
+
}
|
|
1264
|
+
else if (v instanceof Int32Array) {
|
|
1265
|
+
numpyType = "int32";
|
|
1266
|
+
}
|
|
1267
|
+
else if (v instanceof Uint8Array) {
|
|
1268
|
+
numpyType = "uint8";
|
|
1269
|
+
}
|
|
1270
|
+
else if (v instanceof Uint16Array) {
|
|
1271
|
+
numpyType = "uint16";
|
|
1272
|
+
}
|
|
1273
|
+
else if (v instanceof Uint32Array) {
|
|
1274
|
+
numpyType = "uint32";
|
|
1275
|
+
}
|
|
1276
|
+
else if (v instanceof Float32Array) {
|
|
1277
|
+
numpyType = "float32";
|
|
1278
|
+
}
|
|
1279
|
+
else if (v instanceof Float64Array) {
|
|
1280
|
+
numpyType = "float64";
|
|
1281
|
+
}
|
|
1282
|
+
else {
|
|
1283
|
+
// Don't understand it, return as is
|
|
1284
|
+
return v;
|
|
1285
|
+
}
|
|
1286
|
+
var res = {
|
|
1287
|
+
dtype: numpyType,
|
|
1288
|
+
shape: [v.length],
|
|
1289
|
+
value: v.buffer,
|
|
1290
|
+
};
|
|
1291
|
+
return res;
|
|
1292
|
+
}
|
|
1293
|
+
/**
|
|
1294
|
+
* ipywidget JavaScript -> Python serializer
|
|
1295
|
+
*/
|
|
1296
|
+
function js2py_serializer(v, widgetManager) {
|
|
1297
|
+
var res;
|
|
1298
|
+
if (_.isTypedArray(v)) {
|
|
1299
|
+
res = serializeTypedArray(v);
|
|
1300
|
+
}
|
|
1301
|
+
else if (Array.isArray(v)) {
|
|
1302
|
+
// Serialize array elements recursively
|
|
1303
|
+
res = new Array(v.length);
|
|
1304
|
+
for (var i = 0; i < v.length; i++) {
|
|
1305
|
+
res[i] = js2py_serializer(v[i]);
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
else if (_.isPlainObject(v)) {
|
|
1309
|
+
// Serialize object properties recursively
|
|
1310
|
+
res = {};
|
|
1311
|
+
for (var p in v) {
|
|
1312
|
+
if (v.hasOwnProperty(p)) {
|
|
1313
|
+
res[p] = js2py_serializer(v[p]);
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
else if (v === undefined) {
|
|
1318
|
+
// Translate undefined into '_undefined_' sentinal string. The
|
|
1319
|
+
// Python _js_to_py deserializer will convert this into an
|
|
1320
|
+
// Undefined object
|
|
1321
|
+
res = "_undefined_";
|
|
1322
|
+
}
|
|
1323
|
+
else {
|
|
1324
|
+
// Primitive value to transfer directly
|
|
1325
|
+
res = v;
|
|
1326
|
+
}
|
|
1327
|
+
return res;
|
|
1328
|
+
}
|
|
1329
|
+
/**
|
|
1330
|
+
* ipywidget Python -> Javascript deserializer
|
|
1331
|
+
*/
|
|
1332
|
+
function py2js_deserializer(v, widgetManager) {
|
|
1333
|
+
var res;
|
|
1334
|
+
if (Array.isArray(v)) {
|
|
1335
|
+
// Deserialize array elements recursively
|
|
1336
|
+
res = new Array(v.length);
|
|
1337
|
+
for (var i = 0; i < v.length; i++) {
|
|
1338
|
+
res[i] = py2js_deserializer(v[i]);
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
else if (_.isPlainObject(v)) {
|
|
1342
|
+
if ((_.has(v, "value") || _.has(v, "buffer")) &&
|
|
1343
|
+
_.has(v, "dtype") &&
|
|
1344
|
+
_.has(v, "shape")) {
|
|
1345
|
+
// Deserialize special buffer/dtype/shape objects into typed arrays
|
|
1346
|
+
// These objects correspond to numpy arrays on the Python side
|
|
1347
|
+
//
|
|
1348
|
+
// Note plotly.py<=3.1.1 called the buffer object `buffer`
|
|
1349
|
+
// This was renamed `value` in 3.2 to work around a naming conflict
|
|
1350
|
+
// when saving widget state to a notebook.
|
|
1351
|
+
// @ts-ignore
|
|
1352
|
+
var typedarray_type = numpy_dtype_to_typedarray_type[v.dtype];
|
|
1353
|
+
var buffer = _.has(v, "value") ? v.value.buffer : v.buffer.buffer;
|
|
1354
|
+
res = new typedarray_type(buffer);
|
|
1355
|
+
}
|
|
1356
|
+
else {
|
|
1357
|
+
// Deserialize object properties recursively
|
|
1358
|
+
res = {};
|
|
1359
|
+
for (var p in v) {
|
|
1360
|
+
if (v.hasOwnProperty(p)) {
|
|
1361
|
+
res[p] = py2js_deserializer(v[p]);
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
else if (v === "_undefined_") {
|
|
1367
|
+
// Convert the _undefined_ sentinal into undefined
|
|
1368
|
+
res = undefined;
|
|
1369
|
+
}
|
|
1370
|
+
else {
|
|
1371
|
+
// Accept primitive value directly
|
|
1372
|
+
res = v;
|
|
1373
|
+
}
|
|
1374
|
+
return res;
|
|
1375
|
+
}
|
|
1376
|
+
/**
|
|
1377
|
+
* Return whether the input value is a typed array
|
|
1378
|
+
* @param potentialTypedArray
|
|
1379
|
+
* Value to examine
|
|
1380
|
+
* @returns {boolean}
|
|
1381
|
+
*/
|
|
1382
|
+
function isTypedArray(potentialTypedArray) {
|
|
1383
|
+
return (ArrayBuffer.isView(potentialTypedArray) &&
|
|
1384
|
+
!(potentialTypedArray instanceof DataView));
|
|
1385
|
+
}
|
|
1386
|
+
/**
|
|
1387
|
+
* Customizer for use with lodash's mergeWith function
|
|
1388
|
+
*
|
|
1389
|
+
* The customizer ensures that typed arrays are not converted into standard
|
|
1390
|
+
* arrays during the recursive merge
|
|
1391
|
+
*
|
|
1392
|
+
* See: https://lodash.com/docs/latest#mergeWith
|
|
1393
|
+
*/
|
|
1394
|
+
function fullMergeCustomizer(objValue, srcValue, key) {
|
|
1395
|
+
if (key[0] === "_") {
|
|
1396
|
+
// Don't recurse into private properties
|
|
1397
|
+
return null;
|
|
1398
|
+
}
|
|
1399
|
+
else if (isTypedArray(srcValue)) {
|
|
1400
|
+
// Return typed arrays directly, don't recurse inside
|
|
1401
|
+
return srcValue;
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
/**
|
|
1405
|
+
* Reform a Plotly.relayout like operation on an input object
|
|
1406
|
+
*
|
|
1407
|
+
* @param {Object} parentObj
|
|
1408
|
+
* The object that the relayout operation should be applied to
|
|
1409
|
+
* @param {Object} relayoutData
|
|
1410
|
+
* An relayout object as accepted by Plotly.relayout
|
|
1411
|
+
*
|
|
1412
|
+
* Examples:
|
|
1413
|
+
* var d = {foo {bar [5, 10]}};
|
|
1414
|
+
* performRelayoutLike(d, {'foo.bar': [0, 1]});
|
|
1415
|
+
* d -> {foo: {bar: [0, 1]}}
|
|
1416
|
+
*
|
|
1417
|
+
* var d = {foo {bar [5, 10]}};
|
|
1418
|
+
* performRelayoutLike(d, {'baz': 34});
|
|
1419
|
+
* d -> {foo: {bar: [5, 10]}, baz: 34}
|
|
1420
|
+
*
|
|
1421
|
+
* var d = {foo: {bar: [5, 10]};
|
|
1422
|
+
* performRelayoutLike(d, {'foo.baz[1]': 17});
|
|
1423
|
+
* d -> {foo: {bar: [5, 17]}}
|
|
1424
|
+
*
|
|
1425
|
+
*/
|
|
1426
|
+
function performRelayoutLike(parentObj, relayoutData) {
|
|
1427
|
+
// Perform a relayout style operation on a given parent object
|
|
1428
|
+
for (var rawKey in relayoutData) {
|
|
1429
|
+
if (!relayoutData.hasOwnProperty(rawKey)) {
|
|
1430
|
+
continue;
|
|
1431
|
+
}
|
|
1432
|
+
// Extract value for this key
|
|
1433
|
+
var relayoutVal = relayoutData[rawKey];
|
|
1434
|
+
// Set property value
|
|
1435
|
+
if (relayoutVal === null) {
|
|
1436
|
+
_.unset(parentObj, rawKey);
|
|
1437
|
+
}
|
|
1438
|
+
else {
|
|
1439
|
+
_.set(parentObj, rawKey, relayoutVal);
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
/**
|
|
1444
|
+
* Perform a Plotly.restyle like operation on an input object array
|
|
1445
|
+
*
|
|
1446
|
+
* @param {Array.<Object>} parentArray
|
|
1447
|
+
* The object that the restyle operation should be applied to
|
|
1448
|
+
* @param {Object} restyleData
|
|
1449
|
+
* A restyle object as accepted by Plotly.restyle
|
|
1450
|
+
* @param {Array.<Number>} restyleTraces
|
|
1451
|
+
* Array of indexes of the traces that the resytle operation applies to
|
|
1452
|
+
*
|
|
1453
|
+
* Examples:
|
|
1454
|
+
* var d = [{foo: {bar: 1}}, {}, {}]
|
|
1455
|
+
* performRestyleLike(d, {'foo.bar': 2}, [0])
|
|
1456
|
+
* d -> [{foo: {bar: 2}}, {}, {}]
|
|
1457
|
+
*
|
|
1458
|
+
* var d = [{foo: {bar: 1}}, {}, {}]
|
|
1459
|
+
* performRestyleLike(d, {'foo.bar': 2}, [0, 1, 2])
|
|
1460
|
+
* d -> [{foo: {bar: 2}}, {foo: {bar: 2}}, {foo: {bar: 2}}]
|
|
1461
|
+
*
|
|
1462
|
+
* var d = [{foo: {bar: 1}}, {}, {}]
|
|
1463
|
+
* performRestyleLike(d, {'foo.bar': [2, 3, 4]}, [0, 1, 2])
|
|
1464
|
+
* d -> [{foo: {bar: 2}}, {foo: {bar: 3}}, {foo: {bar: 4}}]
|
|
1465
|
+
*
|
|
1466
|
+
*/
|
|
1467
|
+
function performRestyleLike(parentArray, restyleData, restyleTraces) {
|
|
1468
|
+
// Loop over the properties of restyleData
|
|
1469
|
+
for (var rawKey in restyleData) {
|
|
1470
|
+
if (!restyleData.hasOwnProperty(rawKey)) {
|
|
1471
|
+
continue;
|
|
1472
|
+
}
|
|
1473
|
+
// Extract value for property and normalize into a value list
|
|
1474
|
+
var valArray = restyleData[rawKey];
|
|
1475
|
+
if (!Array.isArray(valArray)) {
|
|
1476
|
+
valArray = [valArray];
|
|
1477
|
+
}
|
|
1478
|
+
// Loop over the indexes of the traces being restyled
|
|
1479
|
+
for (var i = 0; i < restyleTraces.length; i++) {
|
|
1480
|
+
// Get trace object
|
|
1481
|
+
var traceInd = restyleTraces[i];
|
|
1482
|
+
var trace = parentArray[traceInd];
|
|
1483
|
+
// Extract value for this trace
|
|
1484
|
+
var singleVal = valArray[i % valArray.length];
|
|
1485
|
+
// Set property value
|
|
1486
|
+
if (singleVal === null) {
|
|
1487
|
+
_.unset(trace, rawKey);
|
|
1488
|
+
}
|
|
1489
|
+
else if (singleVal !== undefined) {
|
|
1490
|
+
_.set(trace, rawKey, singleVal);
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
/**
|
|
1496
|
+
* Perform a Plotly.moveTraces like operation on an input object array
|
|
1497
|
+
* @param parentArray
|
|
1498
|
+
* The object that the moveTraces operation should be applied to
|
|
1499
|
+
* @param currentInds
|
|
1500
|
+
* Array of the current indexes of traces to be moved
|
|
1501
|
+
* @param newInds
|
|
1502
|
+
* Array of the new indexes that traces selected by currentInds should be
|
|
1503
|
+
* moved to.
|
|
1504
|
+
*
|
|
1505
|
+
* Examples:
|
|
1506
|
+
* var d = [{foo: 0}, {foo: 1}, {foo: 2}]
|
|
1507
|
+
* performMoveTracesLike(d, [0, 1], [2, 0])
|
|
1508
|
+
* d -> [{foo: 1}, {foo: 2}, {foo: 0}]
|
|
1509
|
+
*
|
|
1510
|
+
* var d = [{foo: 0}, {foo: 1}, {foo: 2}]
|
|
1511
|
+
* performMoveTracesLike(d, [0, 2], [1, 2])
|
|
1512
|
+
* d -> [{foo: 1}, {foo: 0}, {foo: 2}]
|
|
1513
|
+
*/
|
|
1514
|
+
function performMoveTracesLike(parentArray, currentInds, newInds) {
|
|
1515
|
+
// ### Remove by currentInds in reverse order ###
|
|
1516
|
+
var movingTracesData = [];
|
|
1517
|
+
for (var ci = currentInds.length - 1; ci >= 0; ci--) {
|
|
1518
|
+
// Insert moving parentArray at beginning of the list
|
|
1519
|
+
movingTracesData.splice(0, 0, parentArray[currentInds[ci]]);
|
|
1520
|
+
parentArray.splice(currentInds[ci], 1);
|
|
1521
|
+
}
|
|
1522
|
+
// ### Sort newInds and movingTracesData by newInds ###
|
|
1523
|
+
var newIndexSortedArrays = _(newInds)
|
|
1524
|
+
.zip(movingTracesData)
|
|
1525
|
+
.sortBy(0)
|
|
1526
|
+
.unzip()
|
|
1527
|
+
.value();
|
|
1528
|
+
newInds = newIndexSortedArrays[0];
|
|
1529
|
+
movingTracesData = newIndexSortedArrays[1];
|
|
1530
|
+
// ### Insert by newInds in forward order ###
|
|
1531
|
+
for (var ni = 0; ni < newInds.length; ni++) {
|
|
1532
|
+
parentArray.splice(newInds[ni], 0, movingTracesData[ni]);
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
/**
|
|
1536
|
+
* Remove nested properties from a parent object
|
|
1537
|
+
* @param {Object} parentObj
|
|
1538
|
+
* Parent object from which properties or nested properties should be removed
|
|
1539
|
+
* @param {Array.<Array.<Number|String>>} keyPaths
|
|
1540
|
+
* Array of key paths for properties that should be removed. Each key path
|
|
1541
|
+
* is an array of properties names or array indexes that reference a
|
|
1542
|
+
* property to be removed
|
|
1543
|
+
*
|
|
1544
|
+
* Examples:
|
|
1545
|
+
* var d = {foo: [{bar: 0}, {bar: 1}], baz: 32}
|
|
1546
|
+
* performRemoveProps(d, ['baz'])
|
|
1547
|
+
* d -> {foo: [{bar: 0}, {bar: 1}]}
|
|
1548
|
+
*
|
|
1549
|
+
* var d = {foo: [{bar: 0}, {bar: 1}], baz: 32}
|
|
1550
|
+
* performRemoveProps(d, ['foo[1].bar', 'baz'])
|
|
1551
|
+
* d -> {foo: [{bar: 0}, {}]}
|
|
1552
|
+
*
|
|
1553
|
+
*/
|
|
1554
|
+
function performRemoveProps(parentObj, keyPaths) {
|
|
1555
|
+
for (var i = 0; i < keyPaths.length; i++) {
|
|
1556
|
+
var keyPath = keyPaths[i];
|
|
1557
|
+
_.unset(parentObj, keyPath);
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
/**
|
|
1561
|
+
* Return object that contains all properties in fullObj that are not
|
|
1562
|
+
* identical to the corresponding properties in removeObj
|
|
1563
|
+
*
|
|
1564
|
+
* Properties of fullObj and removeObj may be objects or arrays of objects
|
|
1565
|
+
*
|
|
1566
|
+
* Returned object is a deep clone of the properties of the input objects
|
|
1567
|
+
*
|
|
1568
|
+
* @param {Object} fullObj
|
|
1569
|
+
* @param {Object} removeObj
|
|
1570
|
+
*
|
|
1571
|
+
* Examples:
|
|
1572
|
+
* var fullD = {foo: [{bar: 0}, {bar: 1}], baz: 32}
|
|
1573
|
+
* var removeD = {baz: 32}
|
|
1574
|
+
* createDeltaObject(fullD, removeD)
|
|
1575
|
+
* -> {foo: [{bar: 0}, {bar: 1}]}
|
|
1576
|
+
*
|
|
1577
|
+
* var fullD = {foo: [{bar: 0}, {bar: 1}], baz: 32}
|
|
1578
|
+
* var removeD = {baz: 45}
|
|
1579
|
+
* createDeltaObject(fullD, removeD)
|
|
1580
|
+
* -> {foo: [{bar: 0}, {bar: 1}], baz: 32}
|
|
1581
|
+
*
|
|
1582
|
+
* var fullD = {foo: [{bar: 0}, {bar: 1}], baz: 32}
|
|
1583
|
+
* var removeD = {foo: [{bar: 0}, {bar: 1}]}
|
|
1584
|
+
* createDeltaObject(fullD, removeD)
|
|
1585
|
+
* -> {baz: 32}
|
|
1586
|
+
*
|
|
1587
|
+
*/
|
|
1588
|
+
function createDeltaObject(fullObj, removeObj) {
|
|
1589
|
+
// Initialize result as object or array
|
|
1590
|
+
var res;
|
|
1591
|
+
if (Array.isArray(fullObj)) {
|
|
1592
|
+
res = new Array(fullObj.length);
|
|
1593
|
+
}
|
|
1594
|
+
else {
|
|
1595
|
+
res = {};
|
|
1596
|
+
}
|
|
1597
|
+
// Initialize removeObj to empty object if not specified
|
|
1598
|
+
if (removeObj === null || removeObj === undefined) {
|
|
1599
|
+
removeObj = {};
|
|
1600
|
+
}
|
|
1601
|
+
// Iterate over object properties or array indices
|
|
1602
|
+
for (var p in fullObj) {
|
|
1603
|
+
if (p[0] !== "_" && // Don't consider private properties
|
|
1604
|
+
fullObj.hasOwnProperty(p) && // Exclude parent properties
|
|
1605
|
+
fullObj[p] !== null // Exclude cases where fullObj doesn't
|
|
1606
|
+
// have the property
|
|
1607
|
+
) {
|
|
1608
|
+
// Compute object equality
|
|
1609
|
+
var props_equal;
|
|
1610
|
+
props_equal = _.isEqual(fullObj[p], removeObj[p]);
|
|
1611
|
+
// Perform recursive comparison if props are not equal
|
|
1612
|
+
if (!props_equal || p === "uid") {
|
|
1613
|
+
// Let uids through
|
|
1614
|
+
// property has non-null value in fullObj that doesn't
|
|
1615
|
+
// match the value in removeObj
|
|
1616
|
+
var fullVal = fullObj[p];
|
|
1617
|
+
if (removeObj.hasOwnProperty(p) && typeof fullVal === "object") {
|
|
1618
|
+
// Recurse over object properties
|
|
1619
|
+
if (Array.isArray(fullVal)) {
|
|
1620
|
+
if (fullVal.length > 0 && typeof fullVal[0] === "object") {
|
|
1621
|
+
// We have an object array
|
|
1622
|
+
res[p] = new Array(fullVal.length);
|
|
1623
|
+
for (var i = 0; i < fullVal.length; i++) {
|
|
1624
|
+
if (!Array.isArray(removeObj[p]) || removeObj[p].length <= i) {
|
|
1625
|
+
res[p][i] = fullVal[i];
|
|
1626
|
+
}
|
|
1627
|
+
else {
|
|
1628
|
+
res[p][i] = createDeltaObject(fullVal[i], removeObj[p][i]);
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
else {
|
|
1633
|
+
// We have a primitive array or typed array
|
|
1634
|
+
res[p] = fullVal;
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
else {
|
|
1638
|
+
// object
|
|
1639
|
+
var full_obj = createDeltaObject(fullVal, removeObj[p]);
|
|
1640
|
+
if (Object.keys(full_obj).length > 0) {
|
|
1641
|
+
// new object is not empty
|
|
1642
|
+
res[p] = full_obj;
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
else if (typeof fullVal === "object" && !Array.isArray(fullVal)) {
|
|
1647
|
+
// Return 'clone' of fullVal
|
|
1648
|
+
// We don't use a standard clone method so that we keep
|
|
1649
|
+
// the special case handling of this method
|
|
1650
|
+
res[p] = createDeltaObject(fullVal, {});
|
|
1651
|
+
}
|
|
1652
|
+
else if (fullVal !== undefined && typeof fullVal !== "function") {
|
|
1653
|
+
// No recursion necessary, Just keep value from fullObj.
|
|
1654
|
+
// But skip values with function type
|
|
1655
|
+
res[p] = fullVal;
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
return res;
|
|
1661
|
+
}
|
|
1662
|
+
function randstr(existing, bits, base, _recursion) {
|
|
1663
|
+
if (!base)
|
|
1664
|
+
base = 16;
|
|
1665
|
+
if (bits === undefined)
|
|
1666
|
+
bits = 24;
|
|
1667
|
+
if (bits <= 0)
|
|
1668
|
+
return "0";
|
|
1669
|
+
var digits = Math.log(Math.pow(2, bits)) / Math.log(base);
|
|
1670
|
+
var res = "";
|
|
1671
|
+
var i, b, x;
|
|
1672
|
+
for (i = 2; digits === Infinity; i *= 2) {
|
|
1673
|
+
digits = (Math.log(Math.pow(2, bits / i)) / Math.log(base)) * i;
|
|
1674
|
+
}
|
|
1675
|
+
var rem = digits - Math.floor(digits);
|
|
1676
|
+
for (i = 0; i < Math.floor(digits); i++) {
|
|
1677
|
+
x = Math.floor(Math.random() * base).toString(base);
|
|
1678
|
+
res = x + res;
|
|
1679
|
+
}
|
|
1680
|
+
if (rem) {
|
|
1681
|
+
b = Math.pow(base, rem);
|
|
1682
|
+
x = Math.floor(Math.random() * b).toString(base);
|
|
1683
|
+
res = x + res;
|
|
1684
|
+
}
|
|
1685
|
+
var parsed = parseInt(res, base);
|
|
1686
|
+
if ((existing && existing[res]) ||
|
|
1687
|
+
(parsed !== Infinity && parsed >= Math.pow(2, bits))) {
|
|
1688
|
+
if (_recursion > 10) {
|
|
1689
|
+
console.warn("randstr failed uniqueness");
|
|
1690
|
+
return res;
|
|
1691
|
+
}
|
|
1692
|
+
return randstr(existing, bits, base, (_recursion || 0) + 1);
|
|
1693
|
+
}
|
|
1694
|
+
else
|
|
1695
|
+
return res;
|
|
1696
|
+
}
|
|
1697
|
+
//# sourceMappingURL=Figure.js.map
|