<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Jupyter Blog - QuantStack</title><link href="https://jasongrout.github.io/medium-archive/pelican/" rel="alternate"/><link href="https://jasongrout.github.io/medium-archive/pelican/feeds/author-quantstack.atom.xml" rel="self"/><id>https://jasongrout.github.io/medium-archive/pelican/</id><updated>2023-02-24T11:11:00+00:00</updated><subtitle>The Project Jupyter blog: news, releases, and community stories, archived from blog.jupyter.org.</subtitle><entry><title>Improving the accessibility of Jupyter</title><link href="https://jasongrout.github.io/medium-archive/pelican/posts/2023/improving-the-accessibility-of-jupyter/" rel="alternate"/><published>2023-02-24T11:11:00+00:00</published><updated>2023-02-24T11:11:00+00:00</updated><author><name>QuantStack</name></author><id>tag:jasongrout.github.io,2023-02-24:/medium-archive/pelican/posts/2023/improving-the-accessibility-of-jupyter/</id><summary type="html">&lt;p&gt;Towards a more accessible Jupyter notebook&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Towards a more accessible Jupyter notebook&lt;/p&gt;
&lt;p&gt;The adoption of Jupyter has grown significantly in the past few years — especially in education contexts. The project has become a foundational component of our digital experience, from the first lines of code written by high-school students to the most advanced research and engineering use cases.&lt;/p&gt;
&lt;p&gt;In this context of global adoption, it is even more important to ensure that as many people as possible can use the project. It is estimated that 15% of the population has a disability that may impair their ability to use online services. If we don’t want them to be excluded from learning sciences, technology, and engineering, we must improve the tools to make them usable by everyone…&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;To address this issue, a Jupyter accessibility working group formed and has now become an&lt;/em&gt; &lt;a href="https://jupyter.org/governance/list_of_subprojects.html"&gt;&lt;em&gt;official Jupyter Subproject&lt;/em&gt;&lt;/a&gt; &lt;em&gt;and received&lt;/em&gt; &lt;a href="https://github.com/jupyter/accessibility/blob/main/docs/funding/czi-grant-roadmap.md"&gt;&lt;em&gt;a grant from the Chan Zuckerberg Initiative&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Creating accessible user interfaces is a challenging task as it requires accommodating a broad range of disabilities, including vision, motor, and cognitive impairments. This article presents some of the recent accessibility improvements in the Jupyter Notebook codebase.&lt;/p&gt;
&lt;h3 id="codemirror-6-and-notebook-7"&gt;CodeMirror 6 and Notebook 7&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://github.com/jupyter/enhancement-proposals/pull/79"&gt;Jupyter Notebook 7&lt;/a&gt;, which is the next major release of the Jupyter Notebook frontend, has been rebuilt with modern JupyterLab components and extensions while maintaining the classic Jupyter Notebook user experience. Notebook 7 will be released shortly after JupyterLab 4 and will take advantage of JupyterLab improvements.&lt;/p&gt;
&lt;p&gt;Improving the accessibility of Jupyter had long been impeded by significant obstacles. The primary obstacle was that the text editor underlying the Jupyter Notebook (CodeMirror 5) had major accessibility issues.&lt;/p&gt;
&lt;p&gt;Fortunately, this accessibility bottleneck has been unblocked as JupyterLab has been upgraded to use &lt;a href="https://codemirror.net/6/"&gt;CodeMirror 6&lt;/a&gt;, a complete rewrite of the text editor with a strong focus on accessibility. Although this upgrade required extensive codebase modifications, the changes landed a few months ago and will be available with JupyterLab 4. Jupyter Notebook 7 will benefit from the CodeMirror 6 upgrade.&lt;/p&gt;
&lt;h3 id="initial-accessibility-audits"&gt;&lt;strong&gt;Initial accessibility audits&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Shortly after the &lt;a href="https://github.com/jupyterlab/jupyterlab/issues/10370"&gt;CodeMirror 6 migration&lt;/a&gt; landed, we made an automated audit of the accessibility of Notebook 7 with these changes, and found that the number of warnings and errors reported by Axe Auditor went down from several hundreds to a few dozen, most of which seemed fixable. Encouraged by these results, we decided to work on bringing that count to zero!&lt;/p&gt;
&lt;p&gt;With a series of fixes ranging from simple changes to the DOM structure of components to fixing up base Lumino components (&lt;a href="https://github.com/jupyterlab/lumino"&gt;Lumino&lt;/a&gt; is a JavaScript framework that underlies a lot of the JupyterLab frontend architecture), we were able to make the Notebook 7 codebase pass the Axe Auditor tests with zero error or warning. While we have not reached that yet in JupyterLab, both JupyterLab and Jupyter Notebook benefit from these improvements made for Notebook 7 since they are built from the same components.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Screenshot of the output of the Axe accessibility audit tool on the classic Jupyter notebook user interface with a test notebook, showing a total of 242 errors, including 20 “critical” errors, 88 “serious” errors, and 134 errors of “moderate” severity." src="https://jasongrout.github.io/medium-archive/pelican/posts/2023/improving-the-accessibility-of-jupyter/images/001-0_-v-lL8LJ8DIqlgXb.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Axe Auditor output with the “classic” Notebook UI (v6) with a &lt;a href="https://nbviewer.org/github/waltherg/notebooks/blob/master/2013-12-03-Crank_Nicolson.ipynb"&gt;test notebook.&lt;/a&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure&gt;
&lt;img alt="Screenshot of the output of the Axe accessibility audit tool on the new Jupyter notebook user interface with a same test notebook, showing zero detected errors." src="https://jasongrout.github.io/medium-archive/pelican/posts/2023/improving-the-accessibility-of-jupyter/images/002-0_7imwXY7uST5QSNfi.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Axe Auditor output with the “next” Notebook UI (v7 alpha 13) with the same &lt;a href="https://nbviewer.org/github/waltherg/notebooks/blob/master/2013-12-03-Crank_Nicolson.ipynb"&gt;test notebook&lt;/a&gt;.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Similar results were achieved with the file explorer and text editor tabs of the application.&lt;/p&gt;
&lt;h3 id="beyond-accessibility-audits"&gt;&lt;strong&gt;Beyond accessibility audits&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Improving the accessibility of Jupyter requires more than just addressing issues flagged by automated audit tools and the &lt;a href="https://github.com/jupyter/accessibility"&gt;Jupyter Accessibility Subproject&lt;/a&gt; is working on improving accessibility across the board in Project Jupyter. These results with the Notebook 7 codebase are very encouraging, but working with end-users and getting their feedback will also be necessary to make the user interface truly accessible.&lt;/p&gt;
&lt;p&gt;To address the diversity of accessibility requirements, we will approach specific use cases separately (for example, users with screen readers, or users who can operate a keyboard but not a pointing device). While the resulting changes may improve usability for everyone, we need to learn from users who have specific needs to make meaningful improvements.&lt;/p&gt;
&lt;p&gt;Finally, many of the accessibility challenges in Jupyter stem from the &lt;em&gt;content&lt;/em&gt; of the notebooks, as notebook authors may not follow the best practices to make their content usable by everyone (such as adding alt text to images and figures, or properly using headings to communicate the organization of a notebook). To promote these best practices, Jupyter could provide linting tools that produce inline warnings and hints for notebooks that do not follow these guidelines.&lt;/p&gt;
&lt;h3 id="acknowledgements"&gt;&lt;strong&gt;Acknowledgements&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;The work by Johan Mabille at &lt;a href="https://twitter.com/QuantStack"&gt;&lt;strong&gt;QuantStack&lt;/strong&gt;&lt;/a&gt; on migrating JupyterLab to use CodeMirror 6 was funded by &lt;a href="https://www.twosigma.com/"&gt;&lt;strong&gt;Two Sigma&lt;/strong&gt;&lt;/a&gt;. This upgrade also enabled significant performance improvements in the rendering of Jupyter notebooks, as detailed in this &lt;a href="/posts/2022/accelerating-jupyterlab/"&gt;earlier post&lt;/a&gt; by Frédéric Collonval.&lt;/p&gt;
&lt;p&gt;We are grateful to members of the Jupyter Accessibility Subproject who produced a thorough review of the Notebook 7 UI with a focus on keyboard navigation. This is an example of an issue that cannot be easily detected by auditing tools.&lt;/p&gt;
&lt;h3 id="about-the-authors"&gt;&lt;strong&gt;About the Authors&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://twitter.com/NicolasBrichet_"&gt;&lt;strong&gt;Nicolas Brichet&lt;/strong&gt;&lt;/a&gt; is a scientific software developer at &lt;a href="https://twitter.com/QuantStack"&gt;QuantStack&lt;/a&gt; active in the Jupyter ecosystem. Among other things, Nicolas made significant contributions to the JupyterLab and Voilà projects, and worked on porting the &lt;a href="https://github.com/jupyter/nbgrader/"&gt;nbgrader&lt;/a&gt; package to JupyterLab. Nicolas worked on accessibility improvements in the JupyterLab and Lumino packages.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://twitter.com/JohanMabille"&gt;&lt;strong&gt;Johan Mabille&lt;/strong&gt;&lt;/a&gt; is a technical director at &lt;a href="https://twitter.com/QuantStack"&gt;QuantStack&lt;/a&gt;. He was honored with the Distinguished Contributors award in 2020 for his contributions to the Jupyter project. Among other things, he is one of the main authors of the JupyterLab visual debugger, and the creator of Xeus, a C++ implementation of the Jupyter kernel protocol at the basis of many Jupyter kernels. Johan was responsible for the migration of JupyterLab to CodeMirror 6.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://twitter.com/jtpio"&gt;&lt;strong&gt;Jeremy Tuloup&lt;/strong&gt;&lt;/a&gt; is a technical director at &lt;a href="https://twitter.com/QuantStack"&gt;QuantStack&lt;/a&gt;, and a Jupyter Distinguished Contributor. He is a core maintainer of JupyterLab and Voilà, and the creator of the JupyterLite project. Jeremy is the main initiator of the Notebook 7 project.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Frédéric Collonval&lt;/strong&gt; is a technical director at &lt;a href="https://twitter.com/QuantStack"&gt;QuantStack&lt;/a&gt;, and a Jupyter Distinguished Contributor. He is a core maintainer of the JupyterLab project. Frédéric contributed to the CodeMirror 6 migration and helped numerous new contributors to get their enhancements accepted.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://twitter.com/SylvainCorlay"&gt;&lt;strong&gt;Sylvain Corlay&lt;/strong&gt;&lt;/a&gt; is the founder and CEO of &lt;a href="https://twitter.com/QuantStack"&gt;QuantStack&lt;/a&gt;, and a Jupyter Distinguished Contributor. He has worked on many areas of the Jupyter project, from interactive widgets to language kernels and other core components.&lt;/p&gt;
</content><category term="accessibility"/></entry><entry><title>Interactive GIS in Jupyter with ipyleaflet</title><link href="https://jasongrout.github.io/medium-archive/pelican/posts/2019/interactive-gis-in-jupyter-with-ipyleaflet/" rel="alternate"/><published>2019-09-24T22:54:00+00:00</published><updated>2019-09-25T15:19:00+00:00</updated><author><name>QuantStack</name></author><id>tag:jasongrout.github.io,2019-09-24:/medium-archive/pelican/posts/2019/interactive-gis-in-jupyter-with-ipyleaflet/</id><summary type="html">&lt;p&gt;As Jupyter grew in popularity, a broad ecosystem of data visualization packages based on Jupyter widgets has arisen, bringing even more…&lt;/p&gt;
</summary><content type="html">&lt;p&gt;As Jupyter grew in popularity, a broad ecosystem of visualization packages based on Jupyter widgets has been developed, bringing even more interactivity to the Jupyter world.&lt;/p&gt;
&lt;p&gt;In this article, we dive into Jupyter Interactive Widgets and the &lt;a href="https://github.com/jupyter-widgets/ipyleaflet"&gt;ipyleaflet&lt;/a&gt; package, an interactive maps visualization system for Jupyter.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="A non-interactive map." src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/interactive-gis-in-jupyter-with-ipyleaflet/images/001-1_YA26aVkLDM1KXjNtGu5-Hw.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;A non-interactive map.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="jupyter-widgets"&gt;Jupyter Widgets&lt;/h2&gt;
&lt;p&gt;Jupyter Interactive Widgets are “special objects” that can be instantiated by the user in their code and result in a counterpart component being created in the front-end.&lt;/p&gt;
&lt;p&gt;The core &lt;code&gt;ipywidgets&lt;/code&gt; package provides a collection of controls that Jupyter users can use to build simple UIs as part of their notebooks (sliders, buttons, dropdowns, layout components).&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Basic ipywidgets controls." src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/interactive-gis-in-jupyter-with-ipyleaflet/images/002-1_a8s90I7Kj3DyBjmh_LjAaw.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Basic ipywidgets &lt;strong&gt;controls&lt;/strong&gt;.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;More than a collection of controls, it provides a framework upon which a large ecosystem of components has been built, allowing notebook authors to capture user inputs in very diverse ways.&lt;/p&gt;
&lt;p&gt;Popular libraries built upon interactive widgets include&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/bloomberg/bqplot"&gt;&lt;strong&gt;bqplot&lt;/strong&gt;&lt;/a&gt;, a 2-D plotting system for Jupyter,&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/maartenbreddels/ipyvolume/"&gt;&lt;strong&gt;ipyvolume&lt;/strong&gt;&lt;/a&gt;, a 3-D plotting package based on WebGL and ThreeJS,&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jupyter-widgets/pythreejs"&gt;&lt;strong&gt;PythreeJS&lt;/strong&gt;&lt;/a&gt;, a 3-D scene description package exposing a large part of the ThreeJS API to Jupyter,&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mariobuikhuizen/ipyvuetify"&gt;&lt;strong&gt;ipyvuetify&lt;/strong&gt;&lt;/a&gt;, a large collection of VuetifyJS components exposed to Jupyter,&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/maartenbreddels/ipywebrtc"&gt;&lt;strong&gt;ipywebrtc&lt;/strong&gt;&lt;/a&gt;, a library exposing the features of the WebRTC protocol to Jupyter kernels,&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/twosigma/beakerx"&gt;&lt;strong&gt;beakerx&lt;/strong&gt;&lt;/a&gt;, a collection of widgets, extensions, and kernels for Jupyter,&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;and many more… This list is not comprehensive and dozens of other widget packages have been developed.&lt;/p&gt;
&lt;h3 id="key-aspects-of-jupyter-widgets-include"&gt;Key aspects of Jupyter widgets include:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Bidirectionality&lt;/strong&gt;Widgets are not just meant for display but can also be used to capture user inputs, which can then trigger new computation. Notebook authors can compose sophisticated applications including a variety of components from different packages.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Language Agnosticism&lt;/strong&gt;Built upon the Jupyter ecosystem, the interactive widget protocol used for the synchronization between the kernel and the front-end is well-specified and can be implemented for any kernel.&lt;br&gt;
Back-ends for other languages than Python already exist, such as for C++ (with the &lt;a href="https://github.com/QuantStack/xeus-cling"&gt;xeus-cling&lt;/a&gt; Jupyter kernel), and languages of the JVM such as Clojure or Groovy (with the &lt;a href="http://beakerx.com/"&gt;beakerx&lt;/a&gt; kernels).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Extensibility&lt;/strong&gt;Jupyter widgets are not meant as a monolithic system with one and only one way to achieve a specific task. We strive to provide a foundational layer allowing third-party widget authors to be as inventive as possible.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;A common pattern for Jupyter widget packages has been to bring the capabilities of popular JavaScript visualization frameworks to Jupyter with a bridge based on ipywidgets. This is the case for the ipyleaflet package, as well as pythreejs and ipyvuetify.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Another use case is the development of &lt;em&gt;ad hoc&lt;/em&gt; controls that are not necessarily relevant for a mainstream visualization package, but may be specific to a scientific field. An example is the &lt;a href="https://github.com/erdc/ipymesh"&gt;ipymesh&lt;/a&gt; project by Chris Kees which can be used to draw PSLG (planar straight-line graphs) in the Jupyter notebook.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="ipyleaflet"&gt;ipyleaflet&lt;/h2&gt;
&lt;p&gt;ipyleaflet is a Jupyter - LeafletJS bridge, bringing mapping capabilities to the notebook and JupyterLab.&lt;/p&gt;
&lt;p&gt;Built as a bridge between the LeafletJS package and Jupyter, the ipyleaflet API maps to that of LeafletJS, bringing most of the core features of the package to Jupyter, and enabling a few popular LeafletJS extensions. A small difference is that following the Python coding style, ipyleaflet makes use of &lt;em&gt;snake_case&lt;/em&gt; instead of &lt;em&gt;CamelCase&lt;/em&gt; for attribute names.&lt;/p&gt;
&lt;h3 id="ipyleaflet-features"&gt;ipyleaflet features&lt;/h3&gt;
&lt;p&gt;The main components to the library are layers and controls, respectively items to be displayed on the map, and interactive widgets overlayed on the map area for greater interactivity.&lt;/p&gt;
&lt;p&gt;The first thing for which you may want to change the default value are the zoom level, the position, or the base layer for the map.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Changing the basemap layer in an ipyleaflet map." src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/interactive-gis-in-jupyter-with-ipyleaflet/images/003-1_02DmPnByfXtPkeYnytNvfA.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Changing the basemap layer in an ipyleaflet map.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Maps can be interactively edited in the Jupyter notebook, by dynamically changing or adding layers. In this screenshot, we add a custom layer including a GeoJSON dataset.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: An alternative layer to GeoJSON is GeoData, which lets the user load the data in the form of a GeoPandas dataframe instead of raw GeoJSON.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure&gt;
&lt;img alt="Adding a GeoJSON dataset to an interactive map." src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/interactive-gis-in-jupyter-with-ipyleaflet/images/004-1_3t7T3EGIeA10R0XrrM9ZVw.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Adding a GeoJSON dataset to an interactive map.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;A number of simple primitives are available such as markers and heatmaps. In the following screencast, we show how primitive properties can be linked with other widgets, and used as means to take user input on a map:&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Linking properties of ipyleaflet primitives to other Jupyter widgets." src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/interactive-gis-in-jupyter-with-ipyleaflet/images/005-1_31XAuFgaeln-mrjxxRzdxA.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Linking properties of ipyleaflet primitives to other Jupyter widgets.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The &lt;em&gt;splitmap&lt;/em&gt; control can be used to compare to different set of ipyleaflet layers at the same location.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="The splitmap control." src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/interactive-gis-in-jupyter-with-ipyleaflet/images/006-1_lZT_nX-jH3jcMLFdhTUxXw.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;The &lt;strong&gt;splitmap&lt;/strong&gt; control.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Another interesting layer is the &lt;em&gt;velocity&lt;/em&gt; layer which can be used to display wind velocity data. This control can take data in the form of an &lt;a href="https://github.com/pydata/xarray"&gt;xarray&lt;/a&gt; dataset.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="The velocity layer." src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/interactive-gis-in-jupyter-with-ipyleaflet/images/007-1_u2J2aJy6FfBaFytG0ppruw.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;The &lt;strong&gt;velocity&lt;/strong&gt; layer.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;More classical visualization tools are also available, such as &lt;em&gt;choropleths&lt;/em&gt;.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="A choropleth layer." src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/interactive-gis-in-jupyter-with-ipyleaflet/images/008-1_MbLnLa_LsugvYdBNjGhhQQ.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;A &lt;strong&gt;choropleth&lt;/strong&gt; layer.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id="jupyterlab-integration-with-the-sidecar-and-theming-support"&gt;JupyterLab Integration with the Sidecar and Theming Support&lt;/h3&gt;
&lt;p&gt;ipyleaflet is well integrated with JupyterLab&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ipyleaflet controls make use of the &lt;strong&gt;JupyterLab themes&lt;/strong&gt; for coloring so that they don’t stand out when using e.g. a dark theme.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
&lt;img alt="The support for JupyterLab themes in ipyleaflet." src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/interactive-gis-in-jupyter-with-ipyleaflet/images/009-1_6tCnE8oedSXuEtiGKA1fAA.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;The support for JupyterLab &lt;strong&gt;themes&lt;/strong&gt; in ipyleaflet.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;ipyleaflet can be used in combination with the &lt;a href="https://github.com/jupyter-widgets/jupyterlab-sidecar/"&gt;&lt;strong&gt;JupyterLab sidecar&lt;/strong&gt;&lt;/a&gt; widget.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
&lt;img alt="Using the sidecar widget in JupyterLab to display a map aside of the notebook." src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/interactive-gis-in-jupyter-with-ipyleaflet/images/010-1_eUr0hcPcBInlp125yA7sHg.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Using the &lt;strong&gt;sidecar&lt;/strong&gt; widget in JupyterLab to display a map aside of the notebook.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Together with the sidecar, a map can be programmatically added to the right-side toolbar of the JupyterLab application, and interactively edited in the notebook. This prevents the back-and-forth scrolling often required to see how changes are reflected visually.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The workflow enabled by ipyleaflet in combination with the sidecar is similar to that of the &lt;a href="https://github.com/OpenGeoscience/geonotebook"&gt;geonotebook&lt;/a&gt; project by Christopher Kotfila, Jonathan Beezley, and Dan LaManna from &lt;a href="https://www.kitware.com/"&gt;Kitware&lt;/a&gt;).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure&gt;
&lt;img alt="The geonotebook (which was based on the classic notebook) provided a similar workflow to the lab sidecar." src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/interactive-gis-in-jupyter-with-ipyleaflet/images/011-1_u2dMqR9n5Vwl1ELtpTbVCg.jpg" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;The &lt;strong&gt;geonotebook&lt;/strong&gt; (which was based on the classic notebook) provided a similar workflow to the lab sidecar.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id="a-more-advanced-example"&gt;A more advanced example&lt;/h3&gt;
&lt;p&gt;Combined with other widget libraries such as bqplot or the core ipywidget package, ipyleaflet users can easily compose more complex applications and dashboards. In the following screencast, we explore the wealth-of-nations dataset with a leafletmap, a bqplot line chart and a dropdown widget:&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Exploring the wealth-of-nations dataset with ipyleaflet, bqplot and core ipywidgets." src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/interactive-gis-in-jupyter-with-ipyleaflet/images/012-1_0SvmdK7ykkDXZ4oU-x6QzA.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Exploring the wealth-of-nations dataset with ipyleaflet, bqplot and core ipywidgets.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id="trying-ipyleaflet-online-with-mybinder"&gt;Trying ipyleaflet online with mybinder&lt;/h3&gt;
&lt;p&gt;If you would like to try out ipyleaflet &lt;em&gt;now&lt;/em&gt;, it is possible thanks to the binder project. Just click on the image below!&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mybinder.org/v2/gh/jupyter-widgets/ipyleaflet/stable?filepath=examples"&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/interactive-gis-in-jupyter-with-ipyleaflet/images/013-1_AsxYLD3dKd9Vej3SII_eLg.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="interactive-gis-in-c-xleaflet"&gt;Interactive GIS in C++: xleaflet&lt;/h3&gt;
&lt;p&gt;As mentioned earlier, interactive widgets back-ends for other programming languages have be implemented. There is a C++ back-end for ipywidgets: &lt;a href="https://github.com/QuantStack/xwidgets"&gt;xwidgets&lt;/a&gt; which is the building block for creating other C++ widgets back-ends.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/interactive-gis-in-jupyter-with-ipyleaflet/images/014-0_aPvM-7TR9IbP_NXO.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/QuantStack/xleaflet"&gt;xleaflet&lt;/a&gt; is the C++ - LeafletJS bridge that exposes almost the same API as ipyleaflet, only that you use it from a C++ interpreter! It is based upon xwidgets which brings the bidirectional communication with the front-end.&lt;/p&gt;
&lt;p&gt;You can learn more about the &lt;a href="https://github.com/QuantStack/xeus-cling"&gt;xeus-cling&lt;/a&gt; Jupyter kernel, xwidgets and xleaflet by reading the following &lt;a href="/posts/2018/interpreted-c-for-gis-with-jupyter/"&gt;blogpost&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="xleaflet is the C++ backend to the jupyter-leaflet integration." src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/interactive-gis-in-jupyter-with-ipyleaflet/images/015-1_m2ElLEj6r-6uDqXmA0tqRw.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;&lt;strong&gt;xleaflet&lt;/strong&gt; is the C++ backend to the jupyter-leaflet integration.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id="deploying-ipyleaflet-based-dashboards-with-voila"&gt;Deploying ipyleaflet-based dashboards with Voilà&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/interactive-gis-in-jupyter-with-ipyleaflet/images/016-1_36JTV2RMHwg0DEW6V00d2A.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/QuantStack/voila"&gt;Voilà&lt;/a&gt; is a tool that turns Jupyter notebooks into standalone dashboards. Built upon the Jupyter stack, it inherits the language agnosticism of the ecosystem, and can be used to produce standalone applications based on ipyleaflet.&lt;/p&gt;
&lt;p&gt;A companion project to Voilà is the Voilà gallery project, a public facing set up of JupyterHub serving Voilà dashboard. It is kindly hosted by &lt;a href="https://www.ovh.com/fr/"&gt;OVH&lt;/a&gt;. You can check out the Voilà gallery at URL &lt;a href="https://voila-gallery.org/services/gallery/"&gt;https://voila-gallery.org&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For more resources about &lt;em&gt;voilà&lt;/em&gt;, check out&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the original announcement of the project: &lt;a href="https://blog.jupyter.org/and-voil%C3%A0-f6a2c08a4a93,"&gt;&lt;em&gt;And Voilà!&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;and for the gallery: &lt;a href="/posts/2019/a-gallery-of-voila-examples/"&gt;&lt;em&gt;A Gallery of Voilà Examples&lt;/em&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you check out the Voilà gallery, don’t miss Jeremy Tuloup’s GPX loader demo!&lt;/p&gt;
&lt;h2 id="jupyter-for-geo-sciences"&gt;Jupyter for Geo Sciences&lt;/h2&gt;
&lt;p&gt;Jupyter’s adoption is exploding in the GeoScience space. Notable projects building upon Jupyter include&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://jeodpp.jrc.ec.europa.eu/home/"&gt;&lt;em&gt;&lt;strong&gt;JEODPP&lt;/strong&gt;&lt;/em&gt;&lt;/a&gt; (JRC Earth Observation Data and Processing Platform) is a EU project providing petabyte scale storage and high-throughput computing capacities to facilitate large scale analysis of Earth Observation data. The main front-end to the platform is base on Jupyter. The mapping capability is based on &lt;strong&gt;ipyleaflet&lt;/strong&gt;. End users can request custom visualization that are returned to them in the form of lazily computed tile layers.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pangeo.io"&gt;&lt;em&gt;&lt;strong&gt;Pangeo&lt;/strong&gt;&lt;/em&gt;&lt;/a&gt; is a community platform providing open, reproducible, and scalable sciences. The Pangeo software ecosystem involves open source tools such as xarray, Iris, Dask, Jupyter, and many other packages.&lt;/li&gt;
&lt;li&gt;It was &lt;a href="/posts/2019/jupyter-meets-the-earth/"&gt;recently announced&lt;/a&gt; that the NSF would be funding the UC Berkeley + NCAR “&lt;em&gt;&lt;strong&gt;EarthCube&lt;/strong&gt;&lt;/em&gt;” proposal “Jupyter meets the Earth: Enabling discovery in geoscience through interactive computing at scale”. The plan involves the development of interactive dashboards with &lt;strong&gt;Voilà&lt;/strong&gt; and contributions to the Voilà codebase.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="related-projects"&gt;Related Projects&lt;/h2&gt;
&lt;h3 id="jupyter-gmaps"&gt;Jupyter-gmaps&lt;/h3&gt;
&lt;p&gt;We should mention the &lt;a href="https://github.com/pbugnion/gmaps"&gt;jupyter-gmaps&lt;/a&gt; project by Pascal Bugnion. Jupyter-gmaps is a bridge between Google maps and Jupyter. Just like ipyleaflet, jupyter-gmaps is built upon the jupyter interactive widgets framework but relies on Google maps for the display instead of LeafletJS library.&lt;/p&gt;
&lt;p&gt;This is a high-quality widget by another core developer of ipywidgets. Pascal is also one of the people behind Voilà and the Voilà gallery.&lt;/p&gt;
&lt;h3 id="folium"&gt;Folium&lt;/h3&gt;
&lt;p&gt;The &lt;a href="https://github.com/python-visualization/folium"&gt;Folium&lt;/a&gt; project enables maps visualization in the Jupyter notebook. Just like ipyleaflet, it is based on LeafletJS. Folium was created by Rob Story and is now maintained by Frank Conengmo and Filipe Fernandes.&lt;/p&gt;
&lt;p&gt;A key difference between Folium and ipyleaflet is that ipyleaflet is built upon ipywidgets and allows bidirectional communication between the front-end and the backend enabling the use of the map to capture user input, while Folium is meant for displaying static data only. Folium enables many LeafletJS extensions, some of which may not be available in ipyleaflet at the moment.&lt;/p&gt;
&lt;h2 id="acknowledgements"&gt;Acknowledgements&lt;/h2&gt;
&lt;p&gt;The ipyleaflet project was started in 2015 by &lt;a href="https://twitter.com/ellisonbg?lang=en"&gt;Brian Granger&lt;/a&gt;, and funded by the &lt;a href="https://www.erdc.usace.army.mil/"&gt;ERDC&lt;/a&gt;. The further development by Sylvain Corlay and Martin Renou was supported by &lt;a href="https://quantstack.net/"&gt;QuantStack&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We are grateful to &lt;a href="https://www.ovh.com"&gt;OVH&lt;/a&gt; for kindly hosting the &lt;a href="http://voila-gallery.org"&gt;Voilà gallery&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Other key contributors to Voilà and ipyleaflet that should be thanked here are Maarten Breddels, Pascal Bugnion, and Yuvi Panda. We should also mention the recent contributions by &lt;a href="https://twitter.com/VasavanT"&gt;Vasavan Thirusittampalam&lt;/a&gt; who worked on the full-screen control and better interoperability with geopandas.&lt;/p&gt;
&lt;h2 id="about-the-authors"&gt;About the Authors&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://twitter.com/SylvainCorlay"&gt;Sylvain Corlay&lt;/a&gt;, and &lt;a href="https://twitter.com/martinRenou"&gt;Martin Renou&lt;/a&gt; are Scientific Software Developers at &lt;a href="https://github.com/QuantStack/"&gt;QuantStack&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="sylvain-corlay"&gt;Sylvain Corlay&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/interactive-gis-in-jupyter-with-ipyleaflet/images/017-1_6-g_O5JJQn4uSoAreSq9Pw_2x.jpeg" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sylvain Corlay&lt;/strong&gt; is the founder and CEO of QuantStack.&lt;/p&gt;
&lt;p&gt;As an Open Source Developer, Sylvain contributes to Project Jupyter in the areas of interactive widgets and language kernels and is a steering committee member of the Project. Beyond QuantStack, Sylvain serves as a member of the board of directors of the NumFOCUS foundation. He also co-organizes the PyData Paris Meetup.&lt;/p&gt;
&lt;h3 id="martin-renou"&gt;Martin Renou&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/interactive-gis-in-jupyter-with-ipyleaflet/images/018-1_eZ36LOdroOy_-KBEN8TLlg_2x.jpeg" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Martin Renou&lt;/strong&gt; is a Scientific Software Developer at QuantStack. Prior to joining QuantStack, Martin also worked as a Software developer at Enthought. He studied at the French Aerospace Engineering School ISAE-Supaero, with major in autonomous systems and programming.&lt;/p&gt;
&lt;p&gt;As an open source developer, Martin has worked on a variety of projects, such as SciviJS (a JavaScript 3-D mesh visualization library), Xtensor, and Xeus.&lt;/p&gt;
</content><category term="geoscience"/><category term="science"/><category term="visualization"/></entry><entry><title>Building a Calculator Jupyter Kernel</title><link href="https://jasongrout.github.io/medium-archive/pelican/posts/2019/building-a-calculator-jupyter-kernel/" rel="alternate"/><published>2019-07-16T08:36:00+00:00</published><updated>2019-07-16T09:14:00+00:00</updated><author><name>QuantStack</name></author><id>tag:jasongrout.github.io,2019-07-16:/medium-archive/pelican/posts/2019/building-a-calculator-jupyter-kernel/</id><summary type="html">&lt;p&gt;A step-by-step guide for authoring language kernels with Xeus&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;strong&gt;A step-by-step guide for authoring language kernels with Xeus&lt;/strong&gt;&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="An early device for interactive computing" src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/building-a-calculator-jupyter-kernel/images/001-0_h6rfGRuTgOkwonN9.jpg" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;An early device for interactive computing&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In order to provide a language-agnostic scientific development environment, the &lt;strong&gt;Jupyter project&lt;/strong&gt; is built upon a &lt;a href="https://jupyter-client.readthedocs.io/en/stable/messaging.html"&gt;&lt;em&gt;well-specified protocol&lt;/em&gt;&lt;/a&gt; to communicate with the &lt;em&gt;Kernel&lt;/em&gt;, the part of the infrastructure responsible for executing the code.&lt;/p&gt;
&lt;p&gt;For a programming language to leverage the potential of the Jupyter ecosystem, such as &lt;em&gt;JupyterHub&lt;/em&gt;, &lt;em&gt;JupyterLab&lt;/em&gt;, and &lt;em&gt;interactive widgets&lt;/em&gt;, all that is needed is a &lt;em&gt;Kernel&lt;/em&gt; to be created for that language that is, an executable implementing the specified inter-process communication. Dozens of kernels have already been implemented bringing Jupyter to many programming languages.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;We are completing our engineering degree and interning at QuantStack. We recently attended the&lt;/em&gt; &lt;a href="/posts/2019/jupyter-community-workshop-building-upon-the-jupyter/"&gt;&lt;em&gt;Jupyter Community Workshop&lt;/em&gt;&lt;/a&gt; &lt;em&gt;on the kernel protocol that took place in Paris in late May. In this occasion, we set ourselves to write a new Jupyter kernel.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Today, we are proud to announce the first release of &lt;a href="https://github.com/QuantStack/xeus-calc"&gt;&lt;em&gt;&lt;strong&gt;xeus-calc&lt;/strong&gt;&lt;/em&gt;&lt;/a&gt;, a calculator kernel for Jupyter! xeus-calc is meant to serve as a &lt;em&gt;minimal,&lt;/em&gt; &lt;em&gt;self-contained&lt;/em&gt;example of Jupyter kernel. It is built upon the &lt;a href="https://github.com/QuantStack/xeus/"&gt;&lt;em&gt;&lt;strong&gt;xeus&lt;/strong&gt;&lt;/em&gt;&lt;/a&gt; project, a modern C++ implementation of the protocol. This article is a step-by-step description on how the kernel was implemented.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You may find this post especially useful if you are creating a new programming language and you want it to work in Jupyter from the start.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="xeus"&gt;Xeus&lt;/h2&gt;
&lt;p&gt;Implementing the &lt;a href="https://jupyter-client.readthedocs.io/en/stable/messaging.html"&gt;&lt;strong&gt;Jupyter kernel protocol&lt;/strong&gt;&lt;/a&gt; from scratch may be a tedious and difficult task. One needs to deal with ZMQ sockets and complex concurrency issues, rely on third-party libraries for cryptographically signing messages or parsing JSON efficiently. This is where the &lt;a href="https://github.com/QuantStack/xeus/"&gt;&lt;em&gt;&lt;strong&gt;xeus&lt;/strong&gt;&lt;/em&gt;&lt;/a&gt; project comes into play: it takes all of that burden so that developers can focus on the parts that are specific to their use case.&lt;/p&gt;
&lt;p&gt;In the end, the kernel author only needs to implement a small number of virtual functions inherited from the &lt;code&gt;xinterpreter&lt;/code&gt; class.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;quot;xeus/xinterpreter.hpp&amp;quot;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;quot;nlohmann/json.hpp&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;xeus&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nd"&gt;xinterpreter&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;nl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;nlohmann&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;namespace custom
{
    class custom_interpreter : public xinterpreter
    {
    public:
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;        custom_interpreter() = default;
        virtual ~custom_interpreter() = default;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;     private:
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;override&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;nl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;execute_request_impl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;execution_counter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                      &lt;/span&gt;&lt;span class="nx"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;                                      &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;                                      &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store_history&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="nx"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;nl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nx"&gt;node_type&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;user_expressions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                      &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;allow_stdin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;override&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;nl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;complete_request_impl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                       &lt;/span&gt;&lt;span class="nx"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cursor_pos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;override&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;nl&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inspect_request_impl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                      &lt;/span&gt;&lt;span class="nb nb-Type"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cursor_pos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                      &lt;/span&gt;&lt;span class="nb nb-Type"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;detail_level&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;override&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;nl&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;is_complete_request_impl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;override&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;nl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;kernel_info_request_impl&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;override&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Typically, a kernel author will make use of the C or C++ API of the target programming language and embed the interpreter into the application.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This differs from the &lt;em&gt;wrapper kernel&lt;/em&gt; approach documented in the ipykernel package where kernel authors make use of the kernel protocol implementation of ipykernel, typically spawning a separate process for the interpreter and capturing its standard output.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Jupyter kernels based on xeus include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/QuantStack/xeus-cling"&gt;&lt;em&gt;&lt;strong&gt;xeus-cling&lt;/strong&gt;&lt;/em&gt;&lt;/a&gt;: a C++ kernel built upon the cling C++ interpreter from CERN&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/QuantStack/xeus-python"&gt;&lt;strong&gt;xeus-python&lt;/strong&gt;&lt;/a&gt;: a new Python kernel for Jupyter.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/JuniperKernel/JuniperKernel"&gt;&lt;em&gt;&lt;strong&gt;JuniperKernel&lt;/strong&gt;&lt;/em&gt;&lt;/a&gt;: a new R kernel for Jupyter based on xeus.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this post, instead of calling into the API of an external interpreter, we implement the internal logic of the calculator in the kernel itself.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Exposing the xeus calculator to Jupyter" src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/building-a-calculator-jupyter-kernel/images/002-0_Q2jOwO75XQvNuqaR.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Exposing the xeus calculator to Jupyter&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id="a-calculator-project"&gt;A calculator project&lt;/h3&gt;
&lt;p&gt;First, to implement your own Jupyter kernel, you should install Xeus. You can either download it with conda, or install it from sources as detailed in the &lt;a href="https://github.com/QuantStack/xeus"&gt;&lt;em&gt;&lt;strong&gt;readme&lt;/strong&gt;&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now that the installation is out of the way, let’s focus on the implementation itself.&lt;/p&gt;
&lt;p&gt;Recall that the main class for the calculator kernel must inherit from the &lt;code&gt;xinterpreter&lt;/code&gt;class so that Xeus can correctly route the messages received from the front-end.&lt;/p&gt;
&lt;p&gt;This class defines the behavior of the kernel for each message type that is received from the front-end.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kernel_info_request_impl&lt;/code&gt;: returns the information about the kernel, such as the name, the version or even a “banner”, that is a message that is prompted to console clients upon launch. This is a good place to be creative with ASCII art.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;complete_request_impl&lt;/code&gt;: checks if the code can be completed, by that we mean semantic completion, and makes a suggestion accordingly. This way the user can receive a proposition for an adequate completion to the code he is currently writing. We did not use it during our implementation as you will see later, it is safe to return a JSON with a status value only, if you do not want to handle completion.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;is_complete_request_impl&lt;/code&gt;: whether the submitted code is complete and ready for evaluation. For example, if brackets are not all closed, there is probably more to be typed. This message is not used by the notebook front-end but is required for the console, which shows a continuation prompt for further input if it is deemed incomplete. It also checks whether the code is valid or not. Since the calculator expects single-line inputs, it is safe to return an empty JSON object. This may be refined in the future.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;inspect_request_impl&lt;/code&gt;: concerns documentation. It inspects the code to show useful information to the user. We did not use it in our case and went with the default implementation (that is to return an empty JSON object).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;execute_request_impl&lt;/code&gt;: the main function. An &lt;code&gt;execute_request&lt;/code&gt; message is sent by the front-end to ask the kernel to execute the code on behalf of the user. In the case of the calculator, this means parsing the mathematical expression, evaluating it and returning the result, as described in the next section.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Implementation of the calculator&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;First things first, we need to find a way to parse mathematical expressions. To do so, we turn the user input into &lt;em&gt;&lt;strong&gt;Reverse Polish Notation&lt;/strong&gt;&lt;/em&gt; (or RPN), a name full of meaning for the wisest among our readers (or at least the oldest) who used RPN calculators in high school.&lt;/p&gt;
&lt;p&gt;The RPN, also called &lt;em&gt;&lt;strong&gt;Postfix&lt;/strong&gt;&lt;/em&gt; notation, presents the mathematical expression in a specific way : the operands go first followed by the operator. The main advantage of this notation is how it implicitly displays the precedence of operators.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Reverse Polish Notation illustration" src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/building-a-calculator-jupyter-kernel/images/003-0_7eozUxbipal_WV0c.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Reverse Polish Notation illustration&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The main logic of the calculator is provided by two main functions dealing respectively with parsing and evaluating the user expression and a third one for handling spaces in the expression.&lt;/p&gt;
&lt;p&gt;First we have the parsing function (&lt;code&gt;parse_rpn&lt;/code&gt;) transforming the expression into this representation. For this purpose we implement the &lt;a href="https://en.wikipedia.org/wiki/Shunting-yard_algorithm"&gt;&lt;em&gt;&lt;strong&gt;Shunting-yard algorithm&lt;/strong&gt;&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It is based on the use of a stack data structure to change the order of the elements in the expression, depending on their type : operator, operand or parenthesis.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Transforming a user expression into RPN" src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/building-a-calculator-jupyter-kernel/images/004-0_kJeaW70rAkyeYh5l.jpg" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Transforming a user expression into RPN&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Now that we have the expression turned into RPN (with spaces delimiting operands and operators) we need to do the computation. For this purpose we have the function &lt;code&gt;compute_rpn&lt;/code&gt;. Its implementation is based on a loop through a stringstream (hence the need for space delimiters) which performs operations in the right order.&lt;/p&gt;
&lt;p&gt;Note that the result is not returned as an &lt;code&gt;execute_reply&lt;/code&gt; message but is sent on a broadcasting channel instead, so that other clients to the kernel can also see it. The function &lt;code&gt;execute_reply_impl&lt;/code&gt; actually returns the status of the execution only, as you may see in the code below.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;nl&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;interpreter&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;execute_request_impl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb nb-Type"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;execution_counter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                           &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                           &lt;/span&gt;&lt;span class="nb nb-Type"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/*&lt;/span&gt;&lt;span class="n"&gt;silent&lt;/span&gt;&lt;span class="o"&gt;*/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                           &lt;/span&gt;&lt;span class="nb nb-Type"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/*&lt;/span&gt;&lt;span class="n"&gt;store_history&lt;/span&gt;&lt;span class="o"&gt;*/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                           &lt;/span&gt;&lt;span class="n"&gt;nl&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/*&lt;/span&gt;&lt;span class="n"&gt;user_exprs&lt;/span&gt;&lt;span class="o"&gt;*/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                           &lt;/span&gt;&lt;span class="nb nb-Type"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/*&lt;/span&gt;&lt;span class="n"&gt;allow_stdin&lt;/span&gt;&lt;span class="o"&gt;*/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;nl&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pub_data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Result = &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;publish&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;                          &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;publish_stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;try&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;spaced_code&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;formating_expr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;compute_rpn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parse_rpn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spaced_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                                       &lt;/span&gt;&lt;span class="n"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;                                             &lt;/span&gt;&lt;span class="n"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;pub_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;text/plain&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;publish_execution_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;execution_counter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                 &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pub_data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;                                 &lt;/span&gt;&lt;span class="n"&gt;nl&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;nl&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;jresult&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;jresult&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ok&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;jresult&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;payload&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nl&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;jresult&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;user_expressions&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nl&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;jresult&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;runtime_error&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;nl&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;jresult&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;publish_stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;stderr&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;what&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;jresult&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;error&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;jresult&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And that’s it for our calculator! It is as simple as that.&lt;/p&gt;
&lt;p&gt;Yet remember that Xeus is a library, not a kernel by itself. We still have to create an executable that gathers the interpreter and the library. This is done in a &lt;code&gt;main&lt;/code&gt; function whose implementation looks like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb nb-Type"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb nb-Type"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt;&lt;span class="w"&gt;                       &lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;                           &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Load&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="w"&gt;                           &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;connection.json&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt;                           &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;xeus&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;xconfiguration&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;xeus&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;load_configuration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;                                                   &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;interpreter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="w"&gt;                           &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;interpreter_ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unique_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;xeus_calc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;interpreter&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;                           &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;interpreter_ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;interpreter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_unique&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;xeus_calc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;interpreter&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;                              &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kernel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="w"&gt;                           &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;xeus&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;xkernel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kernel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;                         &lt;/span&gt;&lt;span class="n"&gt;xeus&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;get_user_name&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;                         &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;interpreter&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;                           &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;kernel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;                                                   &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;First, we need to load the configuration file. To do so, we check if one was passed as an argument, otherwise, we look for the connection.json file.&lt;/p&gt;
&lt;p&gt;Then, we instantiate the interpreter that we previously set up. Finally, we can create the kernel with all that we defined beforehand. The kernel constructor accepts more parameters that allow customizing some predefined behaviors. You can find more details in the &lt;a href="https://xeus.readthedocs.io/en/latest/"&gt;&lt;em&gt;&lt;strong&gt;Xeus documentation&lt;/strong&gt;&lt;/em&gt;&lt;/a&gt;. Start the kernel and we are good to go!&lt;/p&gt;
&lt;p&gt;Now that everything is set, we can test out our homemade calculator kernel.&lt;/p&gt;
&lt;p&gt;As you can see in the demonstration below, the code displays step-by-step how the computation is done with RPN. This is done with &lt;code&gt;publish_stream&lt;/code&gt;statements, which is equivalent to &lt;code&gt;std::cout&lt;/code&gt; for the Jupyter notebook, very useful for debugging purposes.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="The final result, a functional calculator!" src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/building-a-calculator-jupyter-kernel/images/005-0_o8XXbdwfzxiC8Nmj.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;The final result, a functional calculator!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;You should now have all the information you need to implement your own Jupyter kernel. As you noticed, the Xeus library makes this task quite simple. All that you have to do is to inherit from the &lt;code&gt;xinterpreter&lt;/code&gt; virtual class and implement the functions related to the messaging protocol. Nothing more is required.&lt;/p&gt;
&lt;p&gt;This project can be found on &lt;a href="https://github.com/QuantStack/xeus-calc"&gt;&lt;em&gt;&lt;strong&gt;GitHub&lt;/strong&gt;&lt;/em&gt;&lt;/a&gt;. Feel free to contribute to the project if you wish to improve it, keeping in mind that xeus-calc should remain lean and simple!&lt;/p&gt;
&lt;p&gt;Note that the current implementation only supports arithmetical operators. However it can be easily extended and we may add functional support in the near future.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Acknowledgments&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We would like to thank the whole &lt;a href="https://quantstack.net/the-team.html"&gt;&lt;strong&gt;QuantStack&lt;/strong&gt;&lt;/a&gt; team for their help throughout the process of making this blog post.&lt;/p&gt;
&lt;p&gt;We are also grateful to the organizers of the &lt;a href="/posts/2019/jupyter-community-workshop-building-upon-the-jupyter/"&gt;&lt;em&gt;&lt;strong&gt;Jupyter community workshop on kernels&lt;/strong&gt;&lt;/em&gt;&lt;/a&gt; as we actually started to endeavor during the event.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;About the authors&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vasavan Thiru&lt;/strong&gt; is completing a master’s degree at &lt;em&gt;Sorbonne Université Pierre &amp;amp; Marie Curie&lt;/em&gt; in applied mathematics for mechanics. He is currently interning as a scientific software developer at QuantStack.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thibault Lacharme&lt;/strong&gt; is finishing a master’s degree in Quantitative Finance at &lt;em&gt;Université Paris Dauphine&lt;/em&gt;. Thibault is currently on his internship as a scientific software developer at QuantStack.&lt;/p&gt;
</content><category term="C++"/><category term="kernels"/><category term="xeus"/></entry><entry><title>And voilà!</title><link href="https://jasongrout.github.io/medium-archive/pelican/posts/2019/and-voila/" rel="alternate"/><published>2019-06-11T17:42:00+00:00</published><updated>2021-01-08T08:38:00+00:00</updated><author><name>QuantStack</name></author><id>tag:jasongrout.github.io,2019-06-11:/medium-archive/pelican/posts/2019/and-voila/</id><summary type="html">&lt;p&gt;… from Jupyter notebooks to standalone applications and dashboards&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;strong&gt;… from Jupyter notebooks to standalone applications and dashboards&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The goal of Project Jupyter is to improve the workflows of researchers, educators, scientists, and other practitioners of scientific computing, from the &lt;em&gt;&lt;strong&gt;exploratory phase&lt;/strong&gt;&lt;/em&gt; of their work to the &lt;em&gt;&lt;strong&gt;communication&lt;/strong&gt;&lt;/em&gt; of the results.&lt;/p&gt;
&lt;p&gt;But interactive notebooks are not the best communication tool for all audiences. While they have proven invaluable to provide a &lt;em&gt;narrative&lt;/em&gt; alongside the source, they are not ideal to address &lt;em&gt;&lt;strong&gt;non-technical readers&lt;/strong&gt;&lt;/em&gt;, who may be put off by the presence of code cells, or the need to run the notebook to see the results. Finally, following the order as the code often results in the most interesting content to be at the &lt;em&gt;&lt;strong&gt;end&lt;/strong&gt;&lt;/em&gt; of the document.&lt;/p&gt;
&lt;p&gt;Another challenge with sharing notebooks is the &lt;em&gt;&lt;strong&gt;security&lt;/strong&gt;&lt;/em&gt; model. How can we offer the interactivity of a notebook making use of e.g. Jupyter widgets without allowing arbitrary code execution by the end user?&lt;/p&gt;
&lt;p&gt;We set ourselves to solve these challenges, and we are happy to announce the first release of &lt;em&gt;&lt;strong&gt;Voilà&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/and-voila/images/001-1_c1xwFRqy99o8nLVxDSqNZg.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Voilà&lt;/strong&gt;&lt;/em&gt; turns Jupyter notebooks into standalone web applications.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Voilà supports &lt;em&gt;&lt;strong&gt;Jupyter interactive widgets&lt;/strong&gt;&lt;/em&gt;, including the roundtrips to the kernel.&lt;/li&gt;
&lt;li&gt;Voilà &lt;em&gt;&lt;strong&gt;does not permit arbitrary code execution&lt;/strong&gt;&lt;/em&gt; by consumers of dashboards.&lt;/li&gt;
&lt;li&gt;Built upon Jupyter standard protocols and file formats, Voilà works with any Jupyter kernel (C++, Python, Julia), making it a &lt;em&gt;&lt;strong&gt;language-agnostic&lt;/strong&gt;&lt;/em&gt; dashboarding system.&lt;/li&gt;
&lt;li&gt;Voilà is extensible. It includes a flexible &lt;em&gt;&lt;strong&gt;template system&lt;/strong&gt;&lt;/em&gt; to produce rich application layouts.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="installation-and-first-time-use"&gt;&lt;strong&gt;Installation and first-time use&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Voilà can be installed from pypi:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pip install voila
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;or conda-forge:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;conda install voila -c conda-forge
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Upon installation, several components are installed, one of which is the &lt;code&gt;voila&lt;/code&gt; command-line utility. You can try it by typing &lt;code&gt;voila notebook.ipynb&lt;/code&gt;. It results in the browser opening to a new tornado application showing markdown cells, rich outputs, and interactive widgets.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="From a notebook to a standalone web application" src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/and-voila/images/002-1_imDFJcYj8k-apbrvIK9ZVQ.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;From a notebook to a standalone web application&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;As you can see in the screencast, Jupyter interactive widgets remain fully functional even when they require computation by the kernel.&lt;/p&gt;
&lt;p&gt;You can immediately try out some of the command-line options to Voilà&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;with &lt;code&gt;--strip_sources=False&lt;/code&gt;, input cells will be included in the resulting web application (as read-only pygment snippets).&lt;/li&gt;
&lt;li&gt;with &lt;code&gt;--theme=dark&lt;/code&gt;, Voilà will make use of the dark JupyterLab theme, which will apply to code cells, widgets and all other visible components.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
&lt;img alt="Making use of the dark theme and including input cells" src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/and-voila/images/003-1_ce142q3rm3TgJZVNEgGWcw.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Making use of the dark theme and including input cells&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Note that code is only shown, voilà does not allow users to edit or execute arbitrary code.&lt;/p&gt;
&lt;h2 id="voilas-execution-model"&gt;Voilà’s execution model&lt;/h2&gt;
&lt;p&gt;The execution model of Voilà is the following: upon connection to a notebook URL, Voilà launches the kernel for that notebook, and runs all the cells as it populates the notebook model with the outputs.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="The execution model of Voilà" src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/and-voila/images/004-1_KZj7rmVqAHmY1b-P-QMPLw.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;The execution model of Voilà&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;After the execution, the associated kernel is not shut down. The notebook is converted to HTML and served to the user. The rendered HTML includes JavaScript that establishes a connection to the kernel. Jupyter interactive widgets referred in cell outputs are rendered and connected to their counterpart in the kernel. The kernel is only shut down when the user closes their browser tab.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;The current version of Voilà only responds to the initial GET request when all the cells have finished running, which may take a long time, but there is&lt;/em&gt; &lt;a href="https://github.com/QuantStack/voila/pull/133"&gt;&lt;em&gt;ongoing work&lt;/em&gt;&lt;/a&gt; &lt;em&gt;on enabling progressive rendering, which should make it into a release soon.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;An important aspect of this execution model is that the front-end does not determine what code is run by the backend. In fact, unless specified otherwise (with option &lt;code&gt;--strip-sources=False&lt;/code&gt;), the source of the rendered notebook does not even make it to the front-end. The instance of the &lt;code&gt;jupyter_server&lt;/code&gt; instantiated by Voilà actually disallows execute requests by default.&lt;/p&gt;
&lt;h2 id="support-for-custom-interactive-widgets"&gt;Support for custom interactive widgets&lt;/h2&gt;
&lt;p&gt;Voilà can render custom Jupyter widget libraries, including (but not limited to) &lt;a href="https://github.com/bloomberg/bqplot"&gt;bqplot&lt;/a&gt;, &lt;a href="https://github.com/jupyter-widgets/ipyleaflet"&gt;ipyleafet&lt;/a&gt;, &lt;a href="https://github.com/maartenbreddels/ipyvolume"&gt;ipyvolume&lt;/a&gt;, &lt;a href="https://github.com/matplotlib/jupyter-matplotlib/"&gt;ipympl&lt;/a&gt;, &lt;a href="https://github.com/QuantStack/ipysheet"&gt;ipysheet&lt;/a&gt;, &lt;a href="https://github.com/plotly/plotly.py"&gt;plotly&lt;/a&gt;, &lt;a href="https://github.com/maartenbreddels/ipywebrtc"&gt;ipywebrtc&lt;/a&gt;, etc.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Including bqplot figures with Voilà" src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/and-voila/images/005-1_iBz5dUYHT5N9dbymPKTGCg.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Including &lt;a href="https://github.com/bloomberg/bqplot"&gt;bqplot&lt;/a&gt; figures with Voilà&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Together with &lt;a href="https://github.com/matplotlib/jupyter-matplotlib/"&gt;ipympl&lt;/a&gt;, Voilà is actually a simple means to render interactive matplotlib figures in a standalone web application:&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Rendering interactive matplotlib figures in a web application with voilà" src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/and-voila/images/006-1_e3k8ZgJoCp0Pm-yZ5Xr0Xg.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Rendering interactive matplotlib figures in a web application with voilà&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="voila-is-language-agnostic"&gt;Voilà is language-agnostic&lt;/h2&gt;
&lt;p&gt;Voilà can be used to produce applications with any Jupyter kernel. The following screencast shows how Voilà can be used to produce a simple dashboard in C++ making use of leaflet.js maps, with the &lt;a href="https://github.com/QuantStack/xeus-cling"&gt;xeus-cling&lt;/a&gt; C++ kernel and the &lt;a href="https://github.com/QuantStack/xleaflet"&gt;xleaflet&lt;/a&gt; package.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="A standalone Voilà page making use of the C++ Jupyter kernel, xeus-cling (input cells display enabled)." src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/and-voila/images/007-1_os2ABw7hEnfd1Dq5pOrTDg.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;A standalone Voilà page making use of the C++ Jupyter kernel, &lt;a href="https://github.com/QuantStack/xeus-cling"&gt;xeus-cling&lt;/a&gt; (input cells display enabled).&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;We hope that Voilà will be a stimulant to other languages (R, Julia, JVM/Java) to provide stronger widgets support.&lt;/p&gt;
&lt;h2 id="richer-layouts-with-voila-templates"&gt;Richer layouts with Voilà templates&lt;/h2&gt;
&lt;p&gt;The main extension point to Voilà is the custom &lt;em&gt;&lt;strong&gt;template system&lt;/strong&gt;&lt;/em&gt;. The HTML served to the end-user is produced from the notebook model by applying a Jinja template, which can be defined by the user.&lt;/p&gt;
&lt;p&gt;An example template for voilà is the &lt;code&gt;voila-gridstack&lt;/code&gt; template, which can be installed from pypi with&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pip install voila-gridstack
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can try it by typing &lt;code&gt;voila notebook.ipynb --template=gridstack&lt;/code&gt;.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Making use of the Gridstack template to produce a dashboard with bqplot charts" src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/and-voila/images/008-1_grVVSeKyw7bXYU7fZmHgQQ.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Making use of the Gridstack template to produce a dashboard with &lt;a href="https://github.com/bloomberg/bqplot/"&gt;bqplot&lt;/a&gt; charts&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The &lt;a href="https://github.com/QuantStack/voila-gridstack/"&gt;gridstack Voilà template&lt;/a&gt; makes use of the cell metadata to lay out the application.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A roadmap item for the gridstack Voilà template is to support the entire spec for the deprecated &lt;a href="https://github.com/jupyter/dashboards"&gt;jupyter dashboards&lt;/a&gt; and to create a WYSIWYG editor for these templates in the form of a JupyterLab extension.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Note that &lt;a href="https://github.com/QuantStack/voila-gridstack/"&gt;voila-gridstack&lt;/a&gt; template is still at an early stage of development.&lt;/p&gt;
&lt;h2 id="how-to-make-custom-voila-templates"&gt;How to make custom Voilà templates?&lt;/h2&gt;
&lt;p&gt;A Voilà template is actually a &lt;em&gt;&lt;strong&gt;folder&lt;/strong&gt;&lt;/em&gt; placed in the standard directory&lt;code&gt;PREFIX/share/jupyter/voila/templates&lt;/code&gt; and which may include&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;nbconvert&lt;/code&gt; templates (the jinja templates used to transform the notebook into HTML)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;static&lt;/code&gt; resources&lt;/li&gt;
&lt;li&gt;custom &lt;code&gt;tornado&lt;/code&gt; templates such as &lt;code&gt;404.html&lt;/code&gt; etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of these are optional. It may also contain a &lt;code&gt;conf.json&lt;/code&gt; file to set up which template to use as a base. The directory structure for a Voilà template is the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;PREFIX/share/jupyter/voila/templates/template_name/
|
├── conf.json                # Template configuration file
├── nbconvert_templates/     # Custom nbconvert templates
├── static/                  # Static directory
└── templates/               # Custom tornado templates
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The Voilà template system can be used to completely override the behavior of the front-end. One can make use of modern JavaScript frameworks such as &lt;a href="https://reactjs.org/"&gt;React&lt;/a&gt; or &lt;a href="https://vuejs.org/"&gt;Vue.js&lt;/a&gt; to produce modern UI including Jupyter widgets and outputs.&lt;/p&gt;
&lt;p&gt;Another example template for Voilà is &lt;code&gt;voila-vuetify&lt;/code&gt;, which is built upon vue.js:&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="The voila-vuetify template makes use of Vue.js" src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/and-voila/images/009-1_HtXNf1rq26u9ss8L-Oo6VQ.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;The &lt;a href="https://github.com/QuantStack/voila-vuetify"&gt;voila-vuetify&lt;/a&gt; template makes use of Vue.js&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;em&gt;The voila-gridstack and voila-vuetify templates are still at an early stage of development, but will be iterated upon quickly in the next weeks as we are exploring templates.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="a-jupyter-server-extension"&gt;A Jupyter server extension&lt;/h2&gt;
&lt;p&gt;Beyond the &lt;code&gt;voila&lt;/code&gt; command-line utility, the Voilà package also include a Jupyter &lt;em&gt;&lt;strong&gt;server extension&lt;/strong&gt;&lt;/em&gt;, so that Voilà dashboards can be served alongside the Jupyter notebook application.&lt;/p&gt;
&lt;p&gt;When Voilà is installed, a running Jupyter server will serve the Voilà web application under &lt;code&gt;BASE_URL/voila&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="the-jupyter-community-workshop-on-dashboarding"&gt;The Jupyter Community Workshop on Dashboarding&lt;/h2&gt;
&lt;p&gt;From June 3rd to June 6th 2019, a &lt;a href="/posts/2019/jupyter-community-workshop-dashboarding-with-project/"&gt;community workshop on dashboarding&lt;/a&gt; with Project Jupyter took place in Paris. Over thirty Jupyter contributors and community members gathered to discuss dashboarding technologies and hack together.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="The participants to the Paris Jupyter community workshop on dashboarding" src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/and-voila/images/010-1_6LggiPlUoCSkP2A1aHp_3w.jpeg" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;The participants to the Paris Jupyter community workshop on dashboarding&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Several dashboarding solutions such as Dash and Panel were presented during the workshop and featured at the &lt;a href="https://www.meetup.com/PyData-Paris/events/261452824/"&gt;PyData Paris Meetup&lt;/a&gt; which was organized on the same week.&lt;/p&gt;
&lt;p&gt;The workshop was also the occasion for several contributors to start working on Voilà. Custom templates, a dashboard gallery, logos and UX mockups for JupyterLab extensions have been developed.&lt;/p&gt;
&lt;p&gt;We will soon publish a more detailed post on the workshop, detailing the many tracks of development that have been explored!&lt;/p&gt;
&lt;h2 id="what-is-coming"&gt;What is coming?&lt;/h2&gt;
&lt;p&gt;There is a lot of planned work around Voilà in the next weeks and months. Current work streams include better &lt;em&gt;&lt;strong&gt;integration with JupyterHub&lt;/strong&gt;&lt;/em&gt; for publicly sharing dashboard between users, as well as &lt;em&gt;&lt;strong&gt;JupyterLab extensions&lt;/strong&gt;&lt;/em&gt; (a &lt;a href="https://github.com/QuantStack/voila/pull/217"&gt;Voilà “preview” extension for notebooks&lt;/a&gt;, and a WYSIWYG editor for dashboard layouts). There are also ongoing discussions with the &lt;a href="https://www.ovh.com/fr/"&gt;OVH&lt;/a&gt; cloud provider (which already supports binder by handling some of its traffic) on hosting a binder-like service dedicated to Voilà dashboards. So stay tuned for more exciting developments!&lt;/p&gt;
&lt;p&gt;Last but not least, we are especially excited about what &lt;em&gt;&lt;strong&gt;you&lt;/strong&gt;&lt;/em&gt; will be building upon Voilà!&lt;/p&gt;
&lt;h2 id="acknowledgments"&gt;Acknowledgments&lt;/h2&gt;
&lt;p&gt;The development of Voilà and related packages at &lt;a href="https://twitter.com/QuantStack"&gt;QuantStack&lt;/a&gt; is sponsored by &lt;a href="http://www.techatbloomberg.com"&gt;&lt;strong&gt;Bloomberg&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We are also grateful to the attendees of the &lt;a href="/posts/2019/jupyter-community-workshop-dashboarding-with-project/"&gt;&lt;strong&gt;Jupyter Community Workshop on Dashboarding&lt;/strong&gt;&lt;/a&gt; for their numerous contributions to Voilà!&lt;/p&gt;
&lt;p&gt;We would like to thank &lt;a href="https://twitter.com/choldgraf"&gt;Chris Holdgraf&lt;/a&gt; for his work on improving documentation, and integration with JupyterHub.&lt;/p&gt;
&lt;p&gt;We should mention &lt;a href="https://twitter.com/yuvipanda"&gt;Yuvi Panda&lt;/a&gt; and &lt;a href="https://twitter.com/pascalbugnion"&gt;Pascal Bugnion&lt;/a&gt; for getting the &lt;code&gt;voila-gallery&lt;/code&gt;project off the ground during the workshop. We are grateful to &lt;a href="https://twitter.com/zrsailer"&gt;Zach Sailer&lt;/a&gt; for his continued work on improving&lt;code&gt;jupyter_server&lt;/code&gt;. We should finally not forget to mention the prior art by &lt;a href="https://twitter.com/pascalbugnion"&gt;Pascal Bugnion&lt;/a&gt; with the Jupyter widgets server which was also an inspiration for Voilà.&lt;/p&gt;
&lt;h2 id="about-the-authors"&gt;About the Authors&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://twitter.com/SylvainCorlay"&gt;&lt;em&gt;Sylvain Corlay&lt;/em&gt;&lt;/a&gt; is the founder and CEO of &lt;a href="https://github.com/QuantStack/"&gt;QuantStack&lt;/a&gt; and a core team member for Project Jupyter.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://twitter.com/maartenbreddels"&gt;Maarten Breddels&lt;/a&gt; is an independent scientific software developer partnering with &lt;a href="https://github.com/QuantStack/"&gt;QuantStack&lt;/a&gt; on numerous projects, and a core developer of Project Jupyter.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/and-voila/images/011-1_F0IS2B1XS6NCxp0Eh7linQ.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
</content><category term="dashboards"/><category term="Voilà"/></entry><entry><title>Authoring Custom Jupyter Widgets</title><link href="https://jasongrout.github.io/medium-archive/pelican/posts/2018/authoring-custom-jupyter-widgets/" rel="alternate"/><published>2018-03-05T12:12:00+00:00</published><updated>2018-03-05T12:12:00+00:00</updated><author><name>QuantStack</name></author><id>tag:jasongrout.github.io,2018-03-05:/medium-archive/pelican/posts/2018/authoring-custom-jupyter-widgets/</id><summary type="html">&lt;p&gt;A Hands-On Guide&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;em&gt;Guest post authored by Olivier Borderies, Olivier Coudray, and Pierre Marion&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://jupyter.org/widgets"&gt;Jupyter interactive widgets&lt;/a&gt; enhance the notebook experience by allowing users to create graphical user interfaces. They enable richer interaction with the data and computing resources.&lt;/p&gt;
&lt;p&gt;While the base &lt;a href="https://github.com/jupyter-widgets/ipywidgets"&gt;ipywidgets&lt;/a&gt; library comes with a &lt;a href="https://ipywidgets.readthedocs.io/en/latest/examples/Widget%20List.html"&gt;number of controls&lt;/a&gt; such as sliders, buttons, and dropdowns, it is in fact much more than a collection of basic controls: it is the foundation of a framework upon which one can build arbitrarily complex interactions.&lt;/p&gt;
&lt;p&gt;Examples of custom widget libraries built upon the foundational package are&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/bloomberg/bqplot"&gt;bqplot&lt;/a&gt;, a d3-Jupyter bridge, and a 2-D plotting library following the constructs of the Grammar of Graphics,&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ellisonbg/ipyleaflet"&gt;ipyleaflet&lt;/a&gt;, a leaflet-Jupyter bridge enabling maps visualization in the Jupyter notebook,&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jovyan/pythreejs"&gt;pythreejs&lt;/a&gt;, a 3-D visualization library bringing the functionalities of Three.js into the Jupyter notebook,&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/maartenbreddels/ipyvolume"&gt;ipyvolume&lt;/a&gt;, a 3-D plotting library also based on Three.js enabling volume rendering, quiver plots and much more.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="jupyter-widgets-a-bridge-between-two-continents"&gt;Jupyter Widgets, a Bridge Between Two Continents&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Jupyter widgets provide a means to bridge the kernel and the rich ecosystem of JavaScript visualization libraries for the web browser. It is an amazing opportunity for scientific developers to use all these resources in their language of choice.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This article is meant to serve as a guide for developers interested in authoring a custom widget library and bridge the gap between the basic examples of the official documentation and fully-fledged visualization libraries like the ones listed above.&lt;/p&gt;
&lt;p&gt;A number of resources are provided alongside the article, including the complete source code of the examples, notebooks, and Binder links.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;In this post, we focus on the&lt;/em&gt; &lt;em&gt;&lt;strong&gt;Python&lt;/strong&gt;&lt;/em&gt; &lt;em&gt;back-end, even though&lt;/em&gt; &lt;a href="https://github.com/jupyter/jupyter/wiki/Jupyter-kernels"&gt;&lt;em&gt;dozens of Jupyter kernels&lt;/em&gt;&lt;/a&gt; &lt;em&gt;exist. The Python kernel is the reference implementation of the Jupyter protocol and remains the most featureful. We should also mention QuantStack’s&lt;/em&gt; &lt;a href="/posts/2017/interactive-workflows-for-c-with-jupyter/"&gt;&lt;em&gt;Xeus&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, a native C++ implementation of Jupyter kernel protocol, which supports interactive widgets. Xeus is used as the foundation for the support of Jupyter widgets for the R and C++ kernels.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure&gt;
&lt;img alt="Xeus: C++ implementation of Jupyter kernel protocol" src="https://jasongrout.github.io/medium-archive/pelican/posts/2018/authoring-custom-jupyter-widgets/images/001-1_7cPVSk9PpumGA6vM79kHwQ.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;&lt;em&gt;Xeus: C++ implementation of Jupyter kernel protocol&lt;/em&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="a-hands-on-guide"&gt;A Hands-On Guide&lt;/h2&gt;
&lt;p&gt;While the Jupyter community is thriving, and we start seeing a growth in the number of custom widget libraries as well. Although the learning curve from the examples of the &lt;a href="https://ipywidgets.readthedocs.io/en/stable/examples/Widget%20Custom.html"&gt;official Jupyter documentation&lt;/a&gt; to authoring state-of-the-art libraries like the ones listed above is steep and may be intimidating.&lt;/p&gt;
&lt;p&gt;We started on this path a few months ago and benefited from guidance from core Jupyter developers along the way. Now, we would like to share the lessons learned. We hope this will help turn this mountain trail into a new silk road!&lt;/p&gt;
&lt;p&gt;Let us start with the ‘Hello World’ example widget from the ipywidgets documentation, before moving on to more advanced use cases.&lt;/p&gt;
&lt;h2 id="1-improving-on-the-hello-world-example-from-the-documentation"&gt;1 — Improving on the Hello-World Example from the Documentation&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;This section is derived from the&lt;/em&gt; &lt;a href="http://ipywidgets.readthedocs.io"&gt;&lt;em&gt;ipywidgets documentation&lt;/em&gt;&lt;/a&gt;&lt;em&gt;. The code snippets are CC-0 licensed.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The idea behind Jupyter widgets is to enable a bi-directional communication channel between the kernel (back-end) and the JavaScript front-end. In Python, widgets are special objects which are automatically synchronized with a counterpart object in the JavaScript front-end. In the back-end, the change events are handled by the &lt;a href="http://traitlets.readthedocs.io/en/stable/"&gt;traitlets&lt;/a&gt; package, which implements the observer pattern, while on the JavaScript side, this is done with the &lt;a href="http://backbonejs.org/"&gt;Backbone.js&lt;/a&gt; library.&lt;/p&gt;
&lt;p&gt;The front-end implementation follows the &lt;a href="https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller"&gt;MVC (Model View Controller) pattern&lt;/a&gt;. This allows the rendering of the same widget in multiple cell outputs, where all views share the same model, analogous to printing out a string variable multiple times.&lt;/p&gt;
&lt;p&gt;The official documentation includes a &lt;a href="https://ipywidgets.readthedocs.io/en/stable/examples/Widget%20Custom.html"&gt;Hello-World example widget&lt;/a&gt;, which offers an example of synchronization from Python to JavaScript, but not the other way around. Our &lt;a href="https://github.com/PierreMarion23/jupyter-widget-hello-world-binder"&gt;jupyter-widget-hello-world-binder&lt;/a&gt; example provides a slightly more advanced version of it which demonstrates the bi-directional communication between the Python kernel and the JavaScript front-end. You can experiment with this widget on Binder or simply check out the example notebook with nbviewer.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mybinder.org/v2/gh/PierreMarion23/jupyter-widget-hello-world-binder/master?filepath=hello_world.ipynb"&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2018/authoring-custom-jupyter-widgets/images/002-1_x6oPwz8nMiy4YIgEpczQHg.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://nbviewer.jupyter.org/github/PierreMarion23/jupyter-widget-hello-world-binder/blob/master/hello_world.ipynb"&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2018/authoring-custom-jupyter-widgets/images/003-1_lK1Zi8_qorxl5ZrL_ZMc7w.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Let us briefly present the main aspects of the implementation.&lt;/p&gt;
&lt;p&gt;The JavaScript front-end defines a custom view by extending the base &lt;code&gt;DOMWidgetView&lt;/code&gt; class from the base package:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HelloView&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;widgets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DOMWidgetView&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value_changed&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;change:value&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value_changed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;value_changed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;el&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;textContent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;value&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The Python back-end extends the corresponding base class from the &lt;code&gt;ipywidgets&lt;/code&gt; package:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="n"&gt;HelloWidget&lt;/span&gt;(&lt;span class="n"&gt;widgets&lt;/span&gt;.&lt;span class="n"&gt;DOMWidget&lt;/span&gt;):
    &lt;span class="n"&gt;_view_name&lt;/span&gt; = &lt;span class="n"&gt;Unicode&lt;/span&gt;(&lt;span class="s"&gt;&amp;#39;HelloView&amp;#39;&lt;/span&gt;).&lt;span class="n"&gt;tag&lt;/span&gt;(&lt;span class="n"&gt;sync&lt;/span&gt;=&lt;span class="nb"&gt;True&lt;/span&gt;)
    &lt;span class="n"&gt;_view_module&lt;/span&gt; = &lt;span class="n"&gt;Unicode&lt;/span&gt;(&lt;span class="s"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;).&lt;span class="n"&gt;tag&lt;/span&gt;(&lt;span class="n"&gt;sync&lt;/span&gt;=&lt;span class="nb"&gt;True&lt;/span&gt;)
    &lt;span class="n"&gt;_view_module_version&lt;/span&gt; = &lt;span class="n"&gt;Unicode&lt;/span&gt;(&lt;span class="s"&gt;&amp;#39;0.1.0&amp;#39;&lt;/span&gt;).&lt;span class="n"&gt;tag&lt;/span&gt;(&lt;span class="n"&gt;sync&lt;/span&gt;=&lt;span class="nb"&gt;True&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;    value = Unicode(&amp;#39;Hello World!&amp;#39;).tag(sync=True)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;value&lt;/code&gt; attribute get synchronized between the back-end and the front-end.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;value_changed&lt;/code&gt; callback, which changes the HTML representation of the widget is attached to changes of the value property with the line:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;this.model.on('change:value', this.value_changed, this);&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;In the &lt;a href="https://ipywidgets.readthedocs.io/en/stable/examples/Widget%20Custom.html"&gt;Hello-World&lt;/a&gt; example from the documentation, there is no way to change the JavaScript &lt;code&gt;value&lt;/code&gt; from the notebook front-end. We have added this feature in order to illustrate the bi-directional synchronization between JavaScript and Python. The idea is to trigger an event in the browser which will update the JavaScript model and then automatically - that’s the magic of ipywidgets - the Python back-end. These additional lines trigger the model update:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// update the JavasScript model&lt;/span&gt;
&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;value&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;formElement&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// sync with Python&lt;/span&gt;
&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;touch&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Conversely, when changing the value from the Python kernel the corresponding JavaScript value gets updated, as explained above.&lt;/p&gt;
&lt;p&gt;Check out the &lt;a href="https://github.com/PierreMarion23/jupyter-widget-hello-world-binder"&gt;jupyter-widget-hello-world-binder&lt;/a&gt; repo for more information. The notebook includes additional details and comments.&lt;/p&gt;
&lt;h2 id="2-first-example-involving-bi-directional-communication"&gt;2 — First Example Involving Bi-Directional Communication&lt;/h2&gt;
&lt;p&gt;In the previous section, widgets were entirely defined in the notebook. We now show how to move the implementation outside of the notebook document and produce a proper installable package.&lt;/p&gt;
&lt;h2 id="21-first-widget"&gt;2.1 — First Widget&lt;/h2&gt;
&lt;p&gt;To help you create your own custom widget, the Jupyter team provides a &lt;a href="https://github.com/jupyter-widgets/widget-cookiecutter"&gt;cookiecutter&lt;/a&gt; template, producing a custom Jupyter widget library containing all the boilerplate for packaging. The cookiecutter is initialized with the hello-world widget from the documentation.&lt;/p&gt;
&lt;p&gt;We used the widget cookiecutter to put the hello-world widget presented in the previous section into a well-organized GitHub repository. It contains&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the Python part in the &lt;code&gt;first_widget&lt;/code&gt; folder&lt;/li&gt;
&lt;li&gt;the JavaScript part in the &lt;code&gt;js&lt;/code&gt; folder.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;README&lt;/code&gt; provides detailed instructions to install the package, together with information about how to enable the Jupyter extension, and tips for custom widget authors. It delves into the technical details a bit more than this overview blog post.&lt;/p&gt;
&lt;p&gt;Now that the basics of two-way synchronization are covered, you can &lt;strong&gt;create arbitrarily complex widgets!&lt;/strong&gt; The key is to identify the data you would like to synchronize between the front-end and the back-end. Then you can set up the events that will update this data when a change is detected using the building blocks above.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Now you can &lt;strong&gt;‘widget-ify’ any JavaScript library!&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="22-barebones-setuppy"&gt;2.2 — Barebones &lt;code&gt;setup.py&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://github.com/jupyter-widgets/widget-cookiecutter/blob/master/%7B%7Bcookiecutter.github_project_name%7D%7D/setup.py"&gt;setup.py&lt;/a&gt; described in the official documentation tries to automate many of the build steps, at the cost of readability. Fortunately, packaging Jupyter widgets will work with the bare-bones &lt;code&gt;setup.py&lt;/code&gt; we provide.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The gain is a clearer, lighter (~100 less lines) &lt;code&gt;setup.py&lt;/code&gt;, giving you a better understanding of what is happening.&lt;/li&gt;
&lt;li&gt;The drawback is that you need one extra step to install the widget from source.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;# Example: d3-slider
$ git clone https://gitlab.com/oscar6echo/jupyter-widget-d3-slider.git
$ cd js
$ npm install
$ cd ..
$ pip install -e .
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gh"&gt;#&lt;/span&gt; Extra line `jupyter nbextension install`
$ jupyter nbextension install --py --symlink --sys-prefix jupyter_widget_d3_slider
$ jupyter nbextension enable --py --sys-prefix jupyter_widget_d3_slider
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;More importantly we thought that it was clearer to keep the build steps of the Python and JavaScript packages separated. Both build processes are well documented, making the steps easier to follow. Finally, the inclusion of compiled JavaScript bundles in the Python package, is more explicit.&lt;/p&gt;
&lt;h2 id="23-side-note-naming-conventions"&gt;2.3 — Side Note: Naming Conventions&lt;/h2&gt;
&lt;p&gt;Naming conventions for Python packages are covered by &lt;a href="https://www.python.org/dev/peps/pep-0008/#package-and-module-names"&gt;PEP8&lt;/a&gt;. They can be a bit tricky in the case of 2-words names like “first-widget”. Where to use underscore (_) or hyphen (-) ? Typically “-” is used in GitHub repositories, and URLs and JavaScript while any folder or file in a Python module can only contain “_”. In the case of a Jupyter widget there is an extra attention point: in the setup.py file, the &lt;code&gt;data_files&lt;/code&gt; argument in the &lt;code&gt;setup&lt;/code&gt; function is a list of tuples. For each, the first element (representing a path in the filesystem) contains “-” as it relates to JavaScript code while the paths in the second contain “_” as they represent paths in the Python package. For a full example see the &lt;a href="https://github.com/ocoudray/FirstWidget"&gt;first-widget&lt;/a&gt; repo and the detailed README.&lt;/p&gt;
&lt;h2 id="3-increasingly-complex-widgets"&gt;3 — Increasingly Complex Widgets&lt;/h2&gt;
&lt;p&gt;We made the following three widgets, gradually adding complexity. The first two examples are meant as educational examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://gitlab.com/oscar6echo/jupyter-widget-d3-slider/"&gt;d3-slider&lt;/a&gt;, a d3.js-based slider,&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ocoudray/jupyter-drawing-pad"&gt;drawing-pad&lt;/a&gt;, a 2-D drawing pad,&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We hope that the last example will become more than a demonstration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/PierreMarion23/ipypivot"&gt;ipypivot&lt;/a&gt;, a visual Pivot Table UI&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In each case, the GitHub repository includes a demo notebook and the required boilerplate for &lt;a href="https://mybinder.org/"&gt;Binder&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="31-d3-slider"&gt;3.1 — d3-slider&lt;/h2&gt;
&lt;p&gt;This &lt;a href="https://gitlab.com/oscar6echo/jupyter-widget-d3-slider/"&gt;custom d3-slider widget&lt;/a&gt; wraps a &lt;a href="https://bl.ocks.org/mbostock/6452972"&gt;simple custom slider&lt;/a&gt; based on the fantastic &lt;a href="https://d3js.org/"&gt;d3.js library&lt;/a&gt;. You can run and try it on the &lt;a href="https://github.com/ocoudray/jupyter-d3-slider-binder"&gt;Binder repo&lt;/a&gt; or watch it on nbviewer.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mybinder.org/v2/gh/ocoudray/jupyter-d3-slider-binder/master?filepath=Slider_d3_demo.ipynb"&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2018/authoring-custom-jupyter-widgets/images/002-1_x6oPwz8nMiy4YIgEpczQHg.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://nbviewer.jupyter.org/urls/gitlab.com/oscar6echo/jupyter-widget-d3-slider/raw/master/notebooks/demo_d3_slider.ipynb"&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2018/authoring-custom-jupyter-widgets/images/003-1_lK1Zi8_qorxl5ZrL_ZMc7w.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="d3-slider widget" src="https://jasongrout.github.io/medium-archive/pelican/posts/2018/authoring-custom-jupyter-widgets/images/004-1_W8oXVTdQ4na6qbkOSpo88w.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;d3-slider widget&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;To install:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;pip&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;jupyter_widget_d3_slider
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="32-drawing-pad"&gt;3.2 — drawing-pad&lt;/h2&gt;
&lt;p&gt;This &lt;a href="https://github.com/ocoudray/jupyter-drawing-pad"&gt;small drawing pad app&lt;/a&gt;, is inspired from &lt;a href="https://codepen.io/anon/pen/aLYeNB"&gt;this codepen&lt;/a&gt;. You can run and try it on the &lt;a href="https://github.com/PierreMarion23/jupyter-widget-drawing-pad-binder"&gt;Binder repo&lt;/a&gt; or watch it on nbviewer.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mybinder.org/v2/gh/PierreMarion23/jupyter-widget-drawing-pad-binder/master?filepath=Demo_drawing_pad.ipynb"&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2018/authoring-custom-jupyter-widgets/images/002-1_x6oPwz8nMiy4YIgEpczQHg.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://nbviewer.jupyter.org/github/ocoudray/jupyter-drawing-pad/blob/master/Example/Demo_drawing_pad.ipynb"&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2018/authoring-custom-jupyter-widgets/images/003-1_lK1Zi8_qorxl5ZrL_ZMc7w.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="drawing pad widget" src="https://jasongrout.github.io/medium-archive/pelican/posts/2018/authoring-custom-jupyter-widgets/images/005-1_32qRaKxSbihtMaetq6jFog.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;drawing pad widget&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;To install:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;pip&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;jupyter-drawing-pad
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="33-ipypivot"&gt;3.3 — ipypivot&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://github.com/PierreMarion23/pivot-table-widget"&gt;ipypivot&lt;/a&gt; widget, wraps the convenient &lt;a href="https://github.com/nicolaskruchten/pivottable"&gt;PivotTable.js library&lt;/a&gt;. You can run and try it on the &lt;a href="https://github.com/PierreMarion23/ipypivot-binder"&gt;binder repo&lt;/a&gt; or watch it on nbviewer.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mybinder.org/v2/gh/PierreMarion23/ipypivot-binder/master?filepath=demo_pivot_table.ipynb"&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2018/authoring-custom-jupyter-widgets/images/002-1_x6oPwz8nMiy4YIgEpczQHg.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://nbviewer.jupyter.org/github/PierreMarion23/ipypivot/blob/master/notebooks/demo_ipypivot.ipynb"&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2018/authoring-custom-jupyter-widgets/images/003-1_lK1Zi8_qorxl5ZrL_ZMc7w.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="ipypivot widget" src="https://jasongrout.github.io/medium-archive/pelican/posts/2018/authoring-custom-jupyter-widgets/images/006-1_FnkBH8yA-PfCNCxXA2PNIw.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;ipypivot widget&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;To install:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;pip&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;ipypivot
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;conda&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;conda-forge&lt;span class="w"&gt; &lt;/span&gt;ipypivot
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;NOTE&lt;em&gt;: The PivotUI widget is a&lt;/em&gt; &lt;a href="https://github.com/PierreMarion23/ipypivot/blob/master/js/lib/widget_pivotui_box.js"&gt;&lt;em&gt;combo of a custom widget and core widgets&lt;/em&gt;&lt;/a&gt;&lt;em&gt;. This modular approach is more flexible (and looks nicer) but the same features can be made in a&lt;/em&gt; &lt;a href="https://github.com/PierreMarion23/ipypivot/blob/alt/js/lib/widget_pivotui.js"&gt;&lt;em&gt;single custom widget&lt;/em&gt;&lt;/a&gt; &lt;em&gt;containing extra buttons and display fields. The&lt;/em&gt; &lt;a href="https://github.com/PierreMarion23/ipypivot/tree/alt"&gt;&lt;em&gt;&lt;code&gt;alt&lt;/code&gt;&lt;/em&gt; &lt;em&gt;branch&lt;/em&gt;&lt;/a&gt; &lt;em&gt;of the repo contains this version.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="34-including-javascript-callbacks"&gt;3.4 — Including JavaScript Callbacks&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://github.com/PierreMarion23/pivot-table-widget"&gt;ipypivot&lt;/a&gt; widget is an example of a widget that transparently wraps a JavaScript library. Transparent in the sense that &lt;strong&gt;all parameters&lt;/strong&gt; of the JavaScript API are exposed, &lt;strong&gt;including functions&lt;/strong&gt;, which are exposed in the form of strings on the Python side. In Python, JavaScript functions can only be strings, so there is an &lt;code&gt;eval()&lt;/code&gt; to convert them to actual JavaScript functions.&lt;/p&gt;
&lt;p&gt;The benefit is that all the functionalities of the JS libraries are exposed to the Python users with a very thin API. Developers can ‘widget-ify’ a large array of interesting libraries, thereby boosting the productivity of a Jupyter notebook user.&lt;/p&gt;
&lt;p&gt;The downside is naturally the security concerns of enabling arbitrary JavaScript code to be injected by the notebook users. It is less a concern in the context of notebooks being shared within a small team of coworkers.&lt;/p&gt;
&lt;p&gt;We are currently exploring means to execute the user-provided arbitrary JavaScript function in a sandboxed fashion, for example using the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe"&gt;iframe &lt;code&gt;srcdoc&lt;/code&gt; field&lt;/a&gt; (Cf. this &lt;a href="https://github.com/oscar6echo/notebook-image-tabs"&gt;repo&lt;/a&gt; for an example, though not in a Jupyter widget context) and messages can be sent back and forth between the main page and an iframe with the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage"&gt;Window.postMessage&lt;/a&gt; function (see this &lt;a href="https://gist.github.com/pbojinov/8965299"&gt;gist&lt;/a&gt; for a bare bones example).&lt;/p&gt;
&lt;h2 id="35-enabling-jupyter-widgets-by-default"&gt;3.5 — Enabling Jupyter Widgets By Default&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;jupyter nbextension enable&lt;/code&gt; command, arguably cumbersome, has become unnecessary as Jupyter widgets can be enabled by default from notebook version 5.3 (included). See this &lt;a href="https://github.com/jupyter/notebook/pull/3116"&gt;PR&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In order to be future-proof, all the widgets in this article include the file which triggers this ‘automatic enable’, and require notebook &amp;gt;= 5.3. Thus the pip-installation of our widgets is a one-line command. However, in dev mode, you still need to install and enable the notebook example (see section 3.1 for an example).&lt;/p&gt;
&lt;p&gt;If you are working with an older version of notebook (run &lt;code&gt;jupyter notebook --version&lt;/code&gt; to check), you will have to run the following command after pip-installing a widget:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;jupyter&lt;span class="w"&gt; &lt;/span&gt;nbextension&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;enable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--py&lt;span class="w"&gt; &lt;/span&gt;--sys-prefix&lt;span class="w"&gt; &lt;/span&gt;name_of_the_widget
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="4-packaging-and-publishing"&gt;4 — Packaging and Publishing&lt;/h2&gt;
&lt;h2 id="41-pypi-and-npm"&gt;4.1 — PyPI and npm&lt;/h2&gt;
&lt;p&gt;If you have followed the “best practices” so far, packaging shouldn’t be an issue. Indeed, the &lt;a href="https://github.com/jupyter-widgets/widget-cookiecutter"&gt;cookiecutter&lt;/a&gt; provides a template of an easily-packageable widget.&lt;/p&gt;
&lt;p&gt;Once your package is ready, you can publish it on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pypi.python.org/pypi"&gt;PyPI&lt;/a&gt; for the package to be pip-installable&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/"&gt;npmjs&lt;/a&gt; for the JavaScript extension, which is necessary to use the widget as a standalone application (outside of the notebook), render it with nbviewer, and also in the JupyterLab context.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To do so, you can follow &lt;a href="https://github.com/ocoudray/first-widget#4---publish-on-pypi-and-npm"&gt;these instructions&lt;/a&gt; in the documentation of &lt;a href="https://github.com/ocoudray/first-widget"&gt;first-widget&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="42-conda-forge"&gt;4.2 — conda-forge&lt;/h2&gt;
&lt;p&gt;Conda has several advantages over pip:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It is a general-purpose package manager, which allows for non-python dependencies.&lt;/li&gt;
&lt;li&gt;Unlike pip, it also has a real dependency solver, which prevents breaking your environments when updating a single package.&lt;/li&gt;
&lt;li&gt;It allows creating virtual environments to isolate your projects.&lt;/li&gt;
&lt;li&gt;It allows for one-line installation of Jupyter extension, including the enabling of the extension as a “post-link” script (temporary advantage: see the previous section).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Conda packages are available on different channels. The default channel is administrated by Anaconda Inc. The usually recommended channel to upload open source projects is conda-forge, as &lt;a href="https://www.anaconda.com/blog/developer-blog/anaconda-build-migration-conda-forge/"&gt;this article&lt;/a&gt; from Anaconda announces. To add this channel to your conda configuration, run the following command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;conda config --add channels conda-forge
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Several steps are needed to publish a package on conda forge, using a so-called ‘recipe’:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;writing the recipe, which describes how to build the package along with the dependencies required for building and running it&lt;/li&gt;
&lt;li&gt;testing the recipe&lt;/li&gt;
&lt;li&gt;publishing the package on the conda-forge GitHub by forking their &lt;a href="https://github.com/conda-forge/staged-recipes"&gt;staged-recipes repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;maintaining the package&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;a href="https://conda.io/docs/user-guide/tasks/build-packages/index.html"&gt;conda doc&lt;/a&gt; and the &lt;a href="https://conda-forge.org/docs/"&gt;conda-forge doc&lt;/a&gt; are very clear and give you much more detailed information about this subject. If you do not want to read the full doc, and jump straight to the necessary information for publishing a new package, you may want to have a look at our &lt;a href="https://github.com/ocoudray/first-widget"&gt;first-widget repo&lt;/a&gt;. The README contains a &lt;a href="https://github.com/ocoudray/first-widget#5---publish-on-conda-forge"&gt;section&lt;/a&gt; describing the publishing process for conda-forge.&lt;/p&gt;
&lt;h2 id="43-automatic-push-script"&gt;4.3 — Automatic Push Script&lt;/h2&gt;
&lt;p&gt;The sequence of steps to update the version of a Jupyter widget and do all the pushing to the various repositories is quite long.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;run npm prepare to build the js in folder &lt;code&gt;static/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Update version in &lt;code&gt;__meta__.py&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;push package to &lt;a href="https://pypi.python.org/pypi"&gt;pypi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;compute package sha256&lt;/li&gt;
&lt;li&gt;tag repo with version&lt;/li&gt;
&lt;li&gt;push to G&lt;a href="https://github.com/"&gt;itHub&lt;/a&gt; / &lt;a href="https://gitlab.com/"&gt;GitLab&lt;/a&gt; / &lt;a href="https://bitbucket.org/"&gt;Bitbucket&lt;/a&gt; including tag&lt;/li&gt;
&lt;li&gt;push js to &lt;a href="https://gist.github.com/npmjs.com"&gt;npmjs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;push to conda-forge (which includes sha256 hash)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you want to automate the process we advise to have a look at Maarten Breddels’ &lt;a href="https://github.com/maartenbreddels/releash"&gt;releash package&lt;/a&gt; (release with relish :-) ), and how it is used in the context of &lt;a href="https://github.com/maartenbreddels/ipyvolume/blob/master/.releash.py"&gt;ipyvolume&lt;/a&gt; and &lt;a href="https://github.com/QuantStack/ipysheet/blob/master/.releash.py"&gt;ipysheet&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="44-binder-and-nbviewer"&gt;4.4 — Binder and nbviewer&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://nbviewer.org/"&gt;nbviewer&lt;/a&gt; and &lt;a href="http://mybinder.org/"&gt;Binder&lt;/a&gt; are two fantastic tools to share both static and live notebooks.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;nbviewer&lt;/strong&gt; requires a URL to a valid notebook JSON file — typically hosted on GitHub/GitLab. &lt;a href="https://ipywidgets.readthedocs.io/en/latest/embedding.html"&gt;To make widgets render in nbviewer&lt;/a&gt;, you need (1) to make the JavaScript package for your widget available on npm, (2) to run the notebook with the corresponding JavaScript extension (with the same version), and (3) to save the notebook widget state (in the ‘Widgets’ tab) before pushing it to GitHub / GitLab.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Binder&lt;/strong&gt; requires a URL to a GitHub repository containing notebooks and a manifest of the dependencies required to run this notebook, which is used to produce a Docker image including all the resources to run the notebook. Check out the &lt;a href="http://mybinder.readthedocs.io/en/latest/faq.html"&gt;mybinder.org documentation&lt;/a&gt; to know how exactly to make use of it. Another resource is the &lt;a href="https://binderhub.readthedocs.io/en/latest/"&gt;BinderHub documentation&lt;/a&gt; if you want to host your own deployment of Binder. Either way we also highly recommend the article &lt;a href="/posts/2017/binder-2-0-a-tech-guide-2017/"&gt;Binder 2.0, a Tech Guide&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="5-conclusion"&gt;5 — Conclusion&lt;/h2&gt;
&lt;p&gt;Hopefully you will have learned something reading this article. We believe in the potential of Jupyter widgets and hope that this intermediate-level article will help getting more people involved in the development of the ecosystem.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: This article only covers the case of the classic Jupyter notebook. The integration with JupyterLab will be covered in a future article!&lt;/p&gt;
&lt;p&gt;If you find bugs or are interested in improving the example widgets presented here, please do not hesitate contact the authors or open a pull request!&lt;/p&gt;
&lt;h2 id="about-the-authors"&gt;About the Authors&lt;/h2&gt;
&lt;p&gt;Alphabetical order:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Olivier Borderies, Société Générale&lt;/li&gt;
&lt;li&gt;Olivier Coudray, Student at École Polytechnique&lt;/li&gt;
&lt;li&gt;Pierre Marion, Student at École Polytechnique&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The software presented in this post was built upon the work of a large number of people including the &lt;strong&gt;Jupyter&lt;/strong&gt; team. We are especially grateful to &lt;a href="https://twitter.com/SylvainCorlay"&gt;Sylvain Corlay&lt;/a&gt;, &lt;a href="https://twitter.com/jason_grout"&gt;Jason Grout&lt;/a&gt;, &lt;a href="https://twitter.com/ivanov"&gt;Paul Ivanov&lt;/a&gt;, and &lt;a href="https://twitter.com/steve_silvester"&gt;Steven Silvester&lt;/a&gt; from the Jupyter Steering Council, as well as &lt;a href="https://twitter.com/maartenbreddels"&gt;Maarten Breddels&lt;/a&gt; and &lt;a href="https://twitter.com/pascalbugnion"&gt;Pascal Bugnion&lt;/a&gt;.&lt;/p&gt;
</content><category term="widgets"/></entry><entry><title>Interactive Workflows for C++ with Jupyter</title><link href="https://jasongrout.github.io/medium-archive/pelican/posts/2017/interactive-workflows-for-c-with-jupyter/" rel="alternate"/><published>2017-11-29T16:33:00+00:00</published><updated>2019-12-25T09:42:00+00:00</updated><author><name>QuantStack</name></author><id>tag:jasongrout.github.io,2017-11-29:/medium-archive/pelican/posts/2017/interactive-workflows-for-c-with-jupyter/</id><summary type="html">&lt;p&gt;Scientists, educators and engineers not only use programming languages to build software systems, but also in interactive workflows, using…&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Scientists, educators and engineers not only use programming languages to build software systems, but also in interactive workflows, using the tools available to &lt;em&gt;explore&lt;/em&gt; a problem and &lt;em&gt;reason&lt;/em&gt; about it.&lt;/p&gt;
&lt;p&gt;Running some code, looking at a visualization, loading data, and running more code. Quick iteration is especially important during the exploratory phase of a project.&lt;/p&gt;
&lt;p&gt;For this kind of workflow, users of the C++ programming language currently have no choice but to use a heterogeneous set of tools that don’t play well with each other, making the whole process cumbersome, and difficult to reproduce.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;We currently lack a good story for interactive computing in C++&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In our opinion, this hurts the productivity of C++ developers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Most of the progress made in software projects comes from incrementalism. Obstacles to fast iteration hinder progress.&lt;/li&gt;
&lt;li&gt;This also makes C++ more difficult to teach. The first hours of a C++ class are rarely rewarding as the students must learn how to set up a small project before writing any code. And then, a lot more time is required before their work can result in any visual outcome.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="project-jupyter-and-interactive-computing"&gt;Project Jupyter and Interactive Computing&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2017/interactive-workflows-for-c-with-jupyter/images/001-1_wOHyKy6fl3ltcBMNpCvC6Q.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;The goal of Project Jupyter is to provide a consistent set of tools for scientific computing and data science workflows, from the exploratory phase of the analysis to the presentation and the sharing of the results. The Jupyter stack was designed to be agnostic of the programming language, and also to allow alternative implementations of any component of the layered architecture (back-ends for programming languages, custom renderers for file types associated with Jupyter). The stack consists of&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a low-level specification for messaging protocols, standardized file formats,&lt;/li&gt;
&lt;li&gt;a reference implementation of these standards,&lt;/li&gt;
&lt;li&gt;applications built on top of these libraries: the Notebook, JupyterLab, Binder, JupyterHub&lt;/li&gt;
&lt;li&gt;and visualization libraries integrated into the Notebook and JupyterLab.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Adoption of the Jupyter ecosystem has skyrocketed in the past years, with millions of users worldwide, over a million Jupyter notebooks shared on GitHub and large-scale deployments of Jupyter in universities, companies and high-performance computing centers.&lt;/p&gt;
&lt;h2 id="jupyter-and-c"&gt;Jupyter and C++&lt;/h2&gt;
&lt;p&gt;One of the main extension points of the Jupyter stack is the &lt;em&gt;kernel&lt;/em&gt;, the part of the infrastructure responsible for executing the user’s code. Jupyter kernels exist for &lt;a href="https://github.com/jupyter/jupyter/wiki/Jupyter-kernels"&gt;numerous programming languages&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Most Jupyter kernels are implemented in the target programming language: the reference implementation &lt;a href="https://github.com/ipython/ipykernel"&gt;ipykernel&lt;/a&gt; in Python, &lt;a href="https://github.com/JuliaLang/IJulia.jl"&gt;IJulia&lt;/a&gt; in Julia, leading to a duplication of effort for the implementation of the protocol. A common denominator to a lot of these interpreted languages is that the interpreter generally exposes a C API, allowing the embedding into a native application. In an effort to consolidate these commonalities and save work for future kernel builders, we developed &lt;em&gt;xeus&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2017/interactive-workflows-for-c-with-jupyter/images/002-1_TKrPv5AvFM3NJ6a7VMu8Tw.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/QuantStack/xeus"&gt;Xeus&lt;/a&gt; is a C++ implementation of the Jupyter kernel protocol. It is not a kernel itself but a library that facilitates the authoring of kernels, and other applications making use of the Jupyter kernel protocol.&lt;/p&gt;
&lt;p&gt;A typical kernel implementation using xeus would in fact make use of the target interpreter &lt;em&gt;as a library.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;There are a number of benefits of using xeus over implementing your kernel in the target language:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Xeus provides a complete implementation of the protocol, enabling a lot of features from the start for kernel authors, who only need to deal with the language bindings.&lt;/li&gt;
&lt;li&gt;Xeus-based kernels can very easily provide a back-end for Jupyter interactive widgets.&lt;/li&gt;
&lt;li&gt;Finally, xeus can be used to implement kernels for domain-specific languages such as SQL flavors. Existing approaches use a Python wrapper. With xeus, the resulting kernel won’t require Python at run-time, leading to large performance benefits.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2017/interactive-workflows-for-c-with-jupyter/images/003-1_Cr_cfHdrgFXHlO15qdNK7w.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Interpreted C++&lt;/strong&gt; is already a reality at CERN with the &lt;a href="https://root.cern.ch/cling"&gt;Cling&lt;/a&gt; C++ interpreter in the context of the &lt;a href="https://root.cern.ch/"&gt;ROOT&lt;/a&gt; data analysis environment.&lt;/p&gt;
&lt;p&gt;As a first example for a kernel based on xeus, we have implemented &lt;a href="https://github.com/QuantStack/xeus-cling"&gt;xeus-cling&lt;/a&gt;, a pure C++ kernel.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Redirection of outputs to the Jupyter front-end, with different styling in the front-end." src="https://jasongrout.github.io/medium-archive/pelican/posts/2017/interactive-workflows-for-c-with-jupyter/images/004-1_NnjISpzZtpy5TOurg0S89A.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Redirection of outputs to the Jupyter front-end, with different styling in the front-end.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Complex features of the C++ programming language such as, polymorphism, templates, lambdas, are supported by the cling interpreter, making the C++ Jupyter notebook a great prototyping and learning platform for the C++ users. See the image below for a demonstration:&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Features of the C++ programming language supported by the cling interpreter" src="https://jasongrout.github.io/medium-archive/pelican/posts/2017/interactive-workflows-for-c-with-jupyter/images/005-1_lGVLY4fL1ytMfT-eWtoXkw.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Features of the C++ programming language supported by the cling interpreter&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Finally, xeus-cling supports live quick-help, fetching the content on &lt;a href="http://en.cppreference.com/w/"&gt;cppreference&lt;/a&gt; in the case of the standard library.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Live help for the C++standard library in the Jupyter notebook" src="https://jasongrout.github.io/medium-archive/pelican/posts/2017/interactive-workflows-for-c-with-jupyter/images/006-1_Igegq0xBebuJV8hy0TGpfg.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Live help for the C++standard library in the Jupyter notebook&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;blockquote&gt;
&lt;p&gt;We realized that we started using the C++ kernel ourselves very early in the development of the project. For quick experimentation, or reproducing bugs. No need to set up a project with a cpp file and complicated project settings for finding the dependencies… Just write some code and hit &lt;strong&gt;Shift+Enter&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Visual output can also be displayed using the rich display mechanism of the Jupyter protocol.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Using Jupyter's rich display mechanism to display an image inline in the notebook" src="https://jasongrout.github.io/medium-archive/pelican/posts/2017/interactive-workflows-for-c-with-jupyter/images/007-1_t_9qAXtdkSXr-0tO9VvOzQ.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Using Jupyter’s rich display mechanism to display an image inline in the notebook&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2017/interactive-workflows-for-c-with-jupyter/images/008-1_OVfmXFAbfjUtGFXYS9fKRA.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;Another important feature of the Jupyter ecosystem are the &lt;a href="http://jupyter.org/widgets"&gt;Jupyter Interactive Widgets&lt;/a&gt;. They allow the user to build graphical interfaces and interactive data visualization inline in the Jupyter notebook. Moreover it is not just a collection of widgets, but a framework that can be built upon, to create arbitrary visual components. Popular interactive widget libraries include&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/bloomberg/bqplot"&gt;bqplot&lt;/a&gt; (2-D plotting with d3.js)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jovyan/pythreejs"&gt;pythreejs&lt;/a&gt; (3-D scene visualization with three.js)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ellisonbg/ipyleaflet"&gt;ipyleaflet&lt;/a&gt; (maps visualization with leaflet.js)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/maartenbreddels/ipyvolume"&gt;ipyvolume&lt;/a&gt; (3-D plotting and volume rendering with three.js)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/arose/nglview"&gt;nglview&lt;/a&gt; (molecular visualization)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Just like the rest of the Jupyter ecosystem, Jupyter interactive widgets were designed as a language-agnostic framework. Other language back-ends can be created reusing the front-end component, which can be installed separately.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/QUantStack/xwidgets"&gt;xwidgets&lt;/a&gt;, which is still at an early stage of development, is a native C++ implementation of the Jupyter widgets protocol. It already provides an implementation for most of the widget types available in the core Jupyter widgets package.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="C++ back-end to the Jupyter interactive widgets" src="https://jasongrout.github.io/medium-archive/pelican/posts/2017/interactive-workflows-for-c-with-jupyter/images/009-1_ro5Ggdstnf0DoqhTUWGq3A.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;C++ back-end to the Jupyter interactive widgets&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Just like with ipywidgets, one can build upon xwidgets and implement C++ back-ends for the Jupyter widget libraries listed earlier, effectively enabling them for the C++ programming language and other xeus-based kernels: xplot, xvolume, xthreejs…&lt;/p&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2017/interactive-workflows-for-c-with-jupyter/images/010-1_yCRYoJFnbtxYkYMRc9AioA.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/QuantStack/xplot"&gt;xplot&lt;/a&gt; is an experimental C++ back-end for the &lt;a href="https://github.com/bloomberg/bqplot"&gt;bqplot&lt;/a&gt; 2-D plotting library. It enables an API following the constructs of the &lt;a href="https://dl.acm.org/citation.cfm?id=1088896"&gt;&lt;em&gt;Grammar of Graphics&lt;/em&gt;&lt;/a&gt; in C++.&lt;/p&gt;
&lt;p&gt;In xplot, every item in a chart is a separate object that can be modified from the back-end, &lt;em&gt;dynamically&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Changing a property of a plot item, a scale, an axis or the figure canvas itself results in the communication of an update message to the front-end, which reflects the new state of the widget visually.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Changing the data of a scatter plot dynamically to update the chart" src="https://jasongrout.github.io/medium-archive/pelican/posts/2017/interactive-workflows-for-c-with-jupyter/images/011-1_Mx2g3JuTG1Cfvkkv0kqtLA.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Changing the data of a scatter plot dynamically to update the chart&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt; the xplot and xwidgets projects are still at an early stage of development and are changing drastically at each release.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Interactive computing environments like Jupyter are not the only missing tool in the C++ world. Two key ingredients to the success of Python as the &lt;em&gt;lingua franca&lt;/em&gt; of data science is the existence of libraries like &lt;a href="http://www.numpy.org/"&gt;NumPy&lt;/a&gt; and &lt;a href="https://pandas.pydata.org/"&gt;Pandas&lt;/a&gt; at the foundation of the ecosystem.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2017/interactive-workflows-for-c-with-jupyter/images/012-1_HsU43Jzp1vJZpX2g8XPJsg.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/QuantStack/xtensor/"&gt;xtensor&lt;/a&gt; is a C++ library meant for numerical analysis with multi-dimensional array expressions.&lt;/p&gt;
&lt;p&gt;xtensor provides&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;an extensible expression system enabling lazy NumPy-style broadcasting.&lt;/li&gt;
&lt;li&gt;an API following the &lt;em&gt;idioms&lt;/em&gt; of the C++ standard library.&lt;/li&gt;
&lt;li&gt;tools to manipulate array expressions and build upon xtensor.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;xtensor exposes an API similar to that of NumPy covering a growing portion of the functionalities. A cheat sheet can be &lt;a href="http://xtensor.readthedocs.io/en/latest/numpy.html"&gt;found in the documentation&lt;/a&gt;:&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Scrolling the NumPy to xtensor cheat sheet" src="https://jasongrout.github.io/medium-archive/pelican/posts/2017/interactive-workflows-for-c-with-jupyter/images/013-1_PBrf5vWYC8VTq_7VUOZCpA.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Scrolling the NumPy to xtensor cheat sheet&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;However, xtensor internals are very different from NumPy. Using modern C++ techniques (template expressions, closure semantics) xtensor is a lazily evaluated library, avoiding the creation of temporary variables and unnecessary memory allocations, even in the case complex expressions involving broadcasting and language bindings.&lt;/p&gt;
&lt;p&gt;Still, from a user perspective, the combination of xtensor with the C++ notebook provides an experience very similar to that of NumPy in a Python notebook.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Using the xtensor array expression library in a C++ notebook" src="https://jasongrout.github.io/medium-archive/pelican/posts/2017/interactive-workflows-for-c-with-jupyter/images/014-1_ULFpg-ePkdUbqqDLJ9VrDw.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Using the xtensor array expression library in a C++ notebook&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In addition to the core library, the xtensor ecosystem has a number of other components&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/QuantStack/xtensor-blas"&gt;&lt;strong&gt;xtensor-blas&lt;/strong&gt;&lt;/a&gt;: the counterpart to the numpy.linalg module.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/egpbos/xtensor-fftw"&gt;&lt;strong&gt;xtensor-fftw&lt;/strong&gt;&lt;/a&gt;: bindings to the &lt;a href="http://www.fftw.org/"&gt;fftw&lt;/a&gt; library.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/QuantStack/xtensor-io"&gt;&lt;strong&gt;xtensor-io&lt;/strong&gt;&lt;/a&gt;: APIs to read and write various file formats (images, audio, NumPy’s NPZ format).&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/wolfv/xtensor_ros"&gt;&lt;strong&gt;xtensor-ros&lt;/strong&gt;&lt;/a&gt;: bindings for ROS, the robot operating system.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/QuantStack/xtensor-python"&gt;&lt;strong&gt;xtensor-python&lt;/strong&gt;&lt;/a&gt;: bindings for the Python programming language, allowing the use of NumPy arrays in-place, using the NumPy C API and the pybind11 library.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/QuantStack/Xtensor.jl"&gt;&lt;strong&gt;xtensor-julia&lt;/strong&gt;&lt;/a&gt;: bindings for the Julia programming language, allowing the use of Julia arrays in-place, using the C API of the Julia interpreter, and the CxxWrap library.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/QuantStack/xtensor-r"&gt;&lt;strong&gt;xtensor-r&lt;/strong&gt;&lt;/a&gt;: bindings for the R programming language, allowing the use of R arrays in-place.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Detailing further the features of the xtensor framework would be beyond the scope of this post.&lt;/p&gt;
&lt;p&gt;If you are interested in trying the various notebooks presented in this post, there is no need to install anything. You can just use &lt;em&gt;binder&lt;/em&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2017/interactive-workflows-for-c-with-jupyter/images/015-1_9cy5Mns_I0eScsmDBjvxDQ.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mybinder.org/"&gt;The Binder project&lt;/a&gt;, which is part of Project Jupyter, enables the deployment of containerized Jupyter notebooks, from a GitHub repository together with a manifest listing the dependencies (as conda packages).&lt;/p&gt;
&lt;p&gt;All the notebooks in the screenshots above can be run online, by just clicking on one of the following links:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mybinder.org/v2/gh/QuantStack/xeus-cling/stable?filepath=notebooks/xcpp.ipynb"&gt;&lt;strong&gt;xeus-cling&lt;/strong&gt;&lt;/a&gt;: the main xeus-cling example notebook,&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mybinder.org/v2/gh/QuantStack/xtensor/stable?filepath=notebooks/xtensor.ipynb"&gt;&lt;strong&gt;xtensor&lt;/strong&gt;&lt;/a&gt;: the C++ N-D array expression library in a C++ notebook,&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mybinder.org/v2/gh/QuantStack/xwidgets/0.11.1?filepath=notebooks/xwidgets.ipynb"&gt;&lt;strong&gt;xwidgets&lt;/strong&gt;&lt;/a&gt;: the C++ back-end for Jupyter interactive widgets,&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mybinder.org/v2/gh/QuantStack/xplot/0.5.0?filepath=notebooks"&gt;&lt;strong&gt;xplot&lt;/strong&gt;&lt;/a&gt;: the C++ back-end to the bqplot 2-D plotting library for Jupyter.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2017/interactive-workflows-for-c-with-jupyter/images/016-1_JwqhpMxMJppEepj7U4fV-g.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/jupyterhub/jupyterhub"&gt;JupyterHub&lt;/a&gt; is the multi-user infrastructure underlying open wide deployments of Jupyter like Binder but also smaller deployments for authenticated users.&lt;/p&gt;
&lt;p&gt;The modular architecture of JupyterHub enables a great variety of scenarios on how users are authenticated, and what service is made available to them. JupyterHub deployment for several hundreds of users have been done in various universities and institutions, including the Paris-Sud University, where the C++ kernel was also installed for the students to use.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In September 2017, the 350 first-year students at Paris-Sud University who took the “&lt;a href="http://nicolas.thiery.name/Enseignement/Info111/"&gt;Info 111: Introduction to Computer&lt;br&gt;
Science&lt;/a&gt;” class wrote their first lines of C++ in a Jupyter notebook.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The use of Jupyter notebooks in the context of teaching C++ proved especially useful for the first classes, where students can focus on the syntax of the language without distractions such as compiling and linking.&lt;/p&gt;
&lt;h2 id="acknowledgements"&gt;Acknowledgements&lt;/h2&gt;
&lt;p&gt;The software presented in this post was built upon the work of a large number of people including the &lt;strong&gt;Jupyter&lt;/strong&gt; team and the &lt;strong&gt;Cling&lt;/strong&gt; developers.&lt;/p&gt;
&lt;p&gt;We are especially grateful to &lt;a href="https://twitter.com/egpbos"&gt;Patrick Bos&lt;/a&gt; (who authored xtensor-fftw), Nicolas Thiéry, Min Ragan Kelley, Thomas Kluyver, Yuvi Panda, Kyle Cranmer, Axel Naumann and Vassil Vassilev.&lt;/p&gt;
&lt;p&gt;We thank the &lt;a href="http://diana-hep.org"&gt;DIANA/HEP&lt;/a&gt; organization for supporting travel to CERN and encouraging the collaboration between Project Jupyter and the ROOT team.&lt;/p&gt;
&lt;p&gt;We are also grateful to the team at &lt;strong&gt;Paris-Sud University&lt;/strong&gt; who worked on the JupyterHub deployment and the class materials, notably &lt;a href="https://twitter.com/pyviv"&gt;Viviane Pons&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The development of xeus, xtensor, xwidgets and related packages at &lt;a href="https://twitter.com/QuantStack"&gt;QuantStack&lt;/a&gt; is sponsored by &lt;a href="http://www.techatbloomberg.com"&gt;&lt;strong&gt;Bloomberg&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="about-the-authors-alphabetical-order"&gt;About the Authors (alphabetical order)&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://twitter.com/SylvainCorlay"&gt;&lt;em&gt;Sylvain Corlay&lt;/em&gt;&lt;/a&gt;, Scientific Software Developer at &lt;a href="https://github.com/QuantStack/"&gt;QuantStack&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://twitter.com/lgouarin"&gt;&lt;em&gt;Loic Gouarin&lt;/em&gt;&lt;/a&gt;, Research Engineer at &lt;a href="https://www.math.u-psud.fr"&gt;Laboratoire de Mathématiques at Orsay&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://twitter.com/johanmabille?lang=en"&gt;&lt;em&gt;Johan Mabille&lt;/em&gt;&lt;/a&gt;, Scientific Software Developer at &lt;a href="https://github.com/QuantStack/"&gt;QuantStack&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://twitter.com/wuoulf"&gt;&lt;em&gt;Wolf Vollprecht&lt;/em&gt;&lt;/a&gt;, Scientific Software Developer at &lt;a href="https://github.com/QuantStack/"&gt;QuantStack&lt;/a&gt;&lt;/p&gt;
</content><category term="C++"/><category term="science"/></entry></feed>