notebook.rst 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. Notebook
  2. ========
  3. Background
  4. ----------
  5. .. _architecture-walkthrough:
  6. A JupyterLab architecture walkthrough from June 16, 2016, provides an overview of the notebook architecture.
  7. .. raw:: html
  8. <div class="jp-youtube-video">
  9. <iframe src="https://www.youtube-nocookie.com/embed/4Qm6oD_Rlw8?rel=0&amp;showinfo=0&amp;start=3326" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
  10. </div>
  11. The most complicated plugin included in the **JupyterLab application**
  12. is the **Notebook plugin**.
  13. The
  14. `NotebookWidgetFactory <../api/classes/notebook.notebookwidgetfactory-1.html>`__
  15. constructs a new
  16. `NotebookPanel <../api/classes/notebook.notebookpanel-1.html>`__
  17. from a model and populates the toolbar with default widgets.
  18. Structure of the Notebook plugin
  19. --------------------------------
  20. The Notebook plugin provides a model and widgets for dealing with
  21. notebook files.
  22. Model
  23. ^^^^^
  24. The
  25. `NotebookModel <../api/classes/notebook.notebookmodel-1.html>`__
  26. contains an observable list of cells.
  27. A `cell
  28. model <../api/classes/cells.cellmodel-1.html>`__
  29. can be:
  30. - a code cell
  31. - a markdown cell
  32. - raw cell
  33. A code cell contains a list of **output models**. The list of cells and
  34. the list of outputs can be observed for changes.
  35. Cell operations
  36. """""""""""""""
  37. The NotebookModel cell list supports single-step operations such as
  38. moving, adding, or deleting cells. Compound cell list operations, such
  39. as undo/redo, are also supported by the NotebookModel. Right now,
  40. undo/redo is only supported on cells and is not supported on notebook
  41. attributes, such as notebook metadata. Currently, undo/redo for
  42. individual cell input content is supported by the CodeMirror editor's
  43. undo feature. (Note: CodeMirror editor's undo does not cover cell
  44. metadata changes.)
  45. Metadata
  46. """"""""
  47. The notebook model and the cell model (i.e. notebook cells) support
  48. getting and setting metadata through an
  49. `IObservableJSON <../api/modules/observables.iobservablejson.html>`__
  50. object. You can use this to get and set notebook/cell metadata,
  51. as well as subscribe to changes to it.
  52. Notebook widget
  53. ^^^^^^^^^^^^^^^
  54. After the NotebookModel is created, the NotebookWidgetFactory constructs
  55. a new NotebookPanel from the model. The NotebookPanel widget is added to
  56. the DockPanel. The **NotebookPanel** contains:
  57. - a
  58. `Toolbar <../api/classes/apputils.toolbar-1.html>`__
  59. - a `Notebook
  60. widget <../api/classes/notebook.notebook-2.html>`__.
  61. The NotebookPanel also adds completion logic.
  62. The **NotebookToolbar** maintains a list of widgets to add to the
  63. toolbar. The **Notebook widget** contains the rendering of the notebook
  64. and handles most of the interaction logic with the notebook itself (such
  65. as keeping track of interactions such as selected and active cells and
  66. also the current edit/command mode).
  67. The NotebookModel cell list provides ways to do fine-grained changes to
  68. the cell list.
  69. Higher level actions using NotebookActions
  70. """"""""""""""""""""""""""""""""""""""""""
  71. Higher-level actions are contained in the
  72. `NotebookActions <../api/classes/notebook.notebookactions-1.html>`__
  73. namespace, which has functions, when given a notebook widget, to run a
  74. cell and select the next cell, merge or split cells at the cursor,
  75. delete selected cells, etc.
  76. Widget hierarchy
  77. """"""""""""""""
  78. A Notebook widget contains a list of `cell
  79. widgets <../api/classes/cells.cell-1.html>`__,
  80. corresponding to the cell models in its cell list.
  81. - Each cell widget contains an
  82. `InputArea <../api/classes/cells.inputarea-1.html>`__,
  83. - which contains n
  84. `CodeEditorWrapper <../api/classes/codeeditor.codeeditorwrapper-1.html>`__,
  85. - which contains a JavaScript CodeMirror instance.
  86. A
  87. `CodeCell <../api/classes/cells.codecell-1.html>`__
  88. also contains an
  89. `OutputArea <../api/classes/outputarea.outputarea-2.html>`__.
  90. An OutputArea is responsible for rendering the outputs in the
  91. `OutputAreaModel <../api/classes/outputarea.outputareamodel-1.html>`__
  92. list. An OutputArea uses a notebook-specific
  93. `RenderMimeRegistry <../api/classes/rendermime.rendermimeregistry-1.html>`__
  94. object to render ``display_data`` output messages.
  95. Rendering output messages
  96. """""""""""""""""""""""""
  97. A **Rendermime plugin** provides a pluggable system for rendering output
  98. messages. Default renderers are provided for markdown, html, images,
  99. text, etc. Extensions can register renderers to be used across the
  100. entire application by registering a handler and mimetype in the
  101. rendermime registry. When a notebook is created, it copies the global
  102. Rendermime singleton so that notebook-specific renderers can be added.
  103. The ipywidgets widget manager is an example of an extension that adds a
  104. notebook-specific renderer, since rendering a widget depends on
  105. notebook-specific widget state.
  106. .. _extend-notebook-plugin:
  107. How to extend the Notebook plugin
  108. ---------------------------------
  109. We'll walk through two notebook extensions:
  110. - adding a button to the toolbar
  111. - adding an ipywidgets extension
  112. Adding a button to the toolbar
  113. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  114. Start from the cookie cutter extension template.
  115. ::
  116. pip install cookiecutter
  117. cookiecutter https://github.com/jupyterlab/extension-cookiecutter-ts
  118. cd my_cookie_cutter_name
  119. Install the dependencies. Note that extensions are built against the
  120. released npm packages, not the development versions.
  121. ::
  122. npm install --save @jupyterlab/notebook @jupyterlab/application @jupyterlab/apputils @jupyterlab/docregistry @lumino/disposable --legacy-peer-deps
  123. Copy the following to ``src/index.ts``:
  124. .. code:: typescript
  125. import {
  126. IDisposable, DisposableDelegate
  127. } from '@lumino/disposable';
  128. import {
  129. JupyterFrontEnd, JupyterFrontEndPlugin
  130. } from '@jupyterlab/application';
  131. import {
  132. ToolbarButton
  133. } from '@jupyterlab/apputils';
  134. import {
  135. DocumentRegistry
  136. } from '@jupyterlab/docregistry';
  137. import {
  138. NotebookActions, NotebookPanel, INotebookModel
  139. } from '@jupyterlab/notebook';
  140. /**
  141. * The plugin registration information.
  142. */
  143. const plugin: JupyterFrontEndPlugin<void> = {
  144. activate,
  145. id: 'my-extension-name:buttonPlugin',
  146. autoStart: true
  147. };
  148. /**
  149. * A notebook widget extension that adds a button to the toolbar.
  150. */
  151. export
  152. class ButtonExtension implements DocumentRegistry.IWidgetExtension<NotebookPanel, INotebookModel> {
  153. /**
  154. * Create a new extension object.
  155. */
  156. createNew(panel: NotebookPanel, context: DocumentRegistry.IContext<INotebookModel>): IDisposable {
  157. let callback = () => {
  158. NotebookActions.runAll(panel.content, context.sessionContext);
  159. };
  160. let button = new ToolbarButton({
  161. className: 'myButton',
  162. iconClass: 'fa fa-fast-forward',
  163. onClick: callback,
  164. tooltip: 'Run All'
  165. });
  166. panel.toolbar.insertItem(0, 'runAll', button);
  167. return new DisposableDelegate(() => {
  168. button.dispose();
  169. });
  170. }
  171. }
  172. /**
  173. * Activate the extension.
  174. */
  175. function activate(app: JupyterFrontEnd) {
  176. app.docRegistry.addWidgetExtension('Notebook', new ButtonExtension());
  177. };
  178. /**
  179. * Export the plugin as default.
  180. */
  181. export default plugin;
  182. And the following to ``style/base.css``:
  183. .. code:: css
  184. .myButton.jp-Button.minimal .jp-Icon {
  185. color: black;
  186. }
  187. Run the following commands:
  188. ::
  189. pip install -e .
  190. pip install jupyter_packaging
  191. jupyter labextension develop . --overwrite
  192. jupyter lab
  193. Open a notebook and observe the new "Run All" button.
  194. The *ipywidgets* third party extension
  195. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  196. This discussion will be a bit confusing since we've been using the term
  197. *widget* to refer to *lumino widgets*. In the discussion below,
  198. *ipython widgets* will be referred to as *ipywidgets*. There is no
  199. intrinsic relation between *lumino widgets* and *ipython widgets*.
  200. The *ipywidgets* extension registers a factory for a notebook *widget*
  201. extension using the `Document
  202. Registry <../api/classes/docregistry.documentregistry-1.html>`__.
  203. The ``createNew()`` function is called with a NotebookPanel and
  204. `DocumentContext <../api/interfaces/docregistry.documentregistry.icontext.html>`__.
  205. The plugin then creates a ipywidget manager (which uses the context to
  206. interact the kernel and kernel's comm manager). The plugin then
  207. registers an ipywidget renderer with the notebook instance's rendermime
  208. (which is specific to that particular notebook).
  209. When an ipywidget model is created in the kernel, a comm message is sent
  210. to the browser and handled by the ipywidget manager to create a
  211. browser-side ipywidget model. When the model is displayed in the kernel,
  212. a ``display_data`` output is sent to the browser with the ipywidget
  213. model id. The renderer registered in that notebook's rendermime is asked
  214. to render the output. The renderer asks the ipywidget manager instance
  215. to render the corresponding model, which returns a JavaScript promise.
  216. The renderer creates a container *lumino widget* which it hands back
  217. synchronously to the OutputArea, and then fills the container with the
  218. rendered *ipywidget* when the promise resolves.