<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Jupyter Blog - dashboards</title><link href="https://jasongrout.github.io/medium-archive/pelican/" rel="alternate"/><link href="https://jasongrout.github.io/medium-archive/pelican/feeds/tag-dashboards.atom.xml" rel="self"/><id>https://jasongrout.github.io/medium-archive/pelican/</id><updated>2024-12-18T08:06:00+00:00</updated><subtitle>The Project Jupyter blog: news, releases, and community stories, archived from blog.jupyter.org.</subtitle><entry><title>Build your Jupyter dashboard using Solara</title><link href="https://jasongrout.github.io/medium-archive/pelican/posts/2024/build-your-jupyter-dashboard-using-solara/" rel="alternate"/><published>2024-12-17T10:26:00+00:00</published><updated>2024-12-18T08:06:00+00:00</updated><author><name>Maarten Breddels</name></author><id>tag:jasongrout.github.io,2024-12-17:/medium-archive/pelican/posts/2024/build-your-jupyter-dashboard-using-solara/</id><summary type="html">&lt;p&gt;Welcome to the first part of a series of articles showing you how to create a dashboard in Jupyter and deploy it as a standalone web app…&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Welcome to the first part of a series of articles showing you how to create a dashboard in Jupyter and deploy it as a standalone web app. Importantly, you won’t need to rewrite your app in a different framework for deployment. We will use a pure Python solution with no JavaScript or CSS required.&lt;/p&gt;
&lt;p&gt;Jupyter notebooks are an incredible data analysis tool since they blend code, visualization, and narrative into a single document. However, we do not want to show the code if the insights must be presented to a non-technical audience.&lt;/p&gt;
&lt;p&gt;Built on top of ipywidgets, the Solara framework integrates into the Jupyter Notebook, Jupyter Lab, and other Jupyter environments and is Open Source. As we will see in a later article, Solara apps can also be deployed efficiently using the Solara server. This, by itself, makes Solara a perfect solution for creating dashboards or data apps.&lt;/p&gt;
&lt;p&gt;In this article, we will create a simple dashboard using Solara’s UI components in Jupyter. The final product will allow an end-user to filter, visualize, and explore a dataset on a map.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="The end result will be a modern looking deploy app" src="https://jasongrout.github.io/medium-archive/pelican/posts/2024/build-your-jupyter-dashboard-using-solara/images/001-1_84N-UBW-fy0xX1pCagIeiw.jpg" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;The end result will be a modern looking deploy app&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="pre-requisites"&gt;Pre-requisites&lt;/h2&gt;
&lt;p&gt;You need to install &lt;code&gt;pandas&lt;/code&gt;, &lt;code&gt;matplotlib&lt;/code&gt;, &lt;code&gt;folium&lt;/code&gt; and &lt;code&gt;solara&lt;/code&gt;. Assuming you are using pip, you can execute on your shell:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pandas&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;matplotlib&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;folium&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;solara&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Or in your notebook&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;%pip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pandas&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;matplotlib&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;folium&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;solara&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="the-start"&gt;The start&lt;/h2&gt;
&lt;p&gt;We will use a subsample of the &lt;a href="https://www.kaggle.com/competitions/sf-crime/data"&gt;San Fransisco crime dataset&lt;/a&gt; which contains information on types of crimes and where they were committed.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://raw.githubusercontent.com/widgetti/solara/master/solara/website/pages/docs/content/04-tutorial/SF_crime_sample.csv.gz"&gt;Download the CSV file&lt;/a&gt; to run this locally, or let the code below sort it out.&lt;/p&gt;
&lt;p&gt;The first thing we do when we read the data is to print it out to see what the dataset contains.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;pandas&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;pd&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;pathlib&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;solara&lt;/span&gt;

&lt;span class="n"&gt;ROOT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;solara&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__file__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;website&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;pages&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;docs&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;content&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;04-tutorial&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ROOT&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;SF_crime_sample.csv.gz&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;https://raw.githubusercontent.com/widgetti/solara/master/solara/website/pages/docs/content/04-tutorial/SF_crime_sample.csv&amp;quot;&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;df_crime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;df_crime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;df_crime&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;figure&gt;
&lt;img alt="Pandas printout of the Crime dataset Dataframe" src="https://jasongrout.github.io/medium-archive/pelican/posts/2024/build-your-jupyter-dashboard-using-solara/images/002-1_bctoyIMn6I60D6gzMq-wjQ.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Pandas printout of the Crime dataset Dataframe&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The data looks clean, but since we will work with the &lt;code&gt;Category&lt;/code&gt; and &lt;code&gt;PdDistrict&lt;/code&gt; column data, let us convert those columns to title case.&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;df_crime&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Category&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df_crime&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Category&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;df_crime&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;PdDistrict&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df_crime&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;PdDistrict&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;df_crime&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;figure&gt;
&lt;img alt="Category and PdDistrict columns nicely formatted with title casing" src="https://jasongrout.github.io/medium-archive/pelican/posts/2024/build-your-jupyter-dashboard-using-solara/images/003-1_3qlsT6qyJsLyRB9Ded461Q.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Category and PdDistrict columns nicely formatted with title casing&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Using proper software engineering practices, we write a function that filters a dataframe to contain only the rows that match our chosen districts and categories.&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;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;crime_filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;district_values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;category_values&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;df_dist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;PdDistrict&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;district_values&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;df_category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df_dist&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;df_dist&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Category&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;category_values&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;df_category&lt;/span&gt;

&lt;span class="n"&gt;dff_crime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;crime_filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df_crime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Bayview&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Northern&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Vandalism&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Assault&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Robbery&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now, with our filtered dataset, we create two bar charts. We use regular Pandas and Matplotlib, but Seaborn or Plotly are also appropriate choices.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;matplotlib.pyplot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;plt&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;crime_charts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;cat_unique&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Category&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value_counts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;cat_unique&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cat_unique&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reset_index&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;dist_unique&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;PdDistrict&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value_counts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;dist_unique&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dist_unique&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reset_index&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ax1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ax2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subplots&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&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="n"&gt;figsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;ax1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cat_unique&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Category&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;cat_unique&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;count&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;ax1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Amount of Criminal Case Based on Category&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dist_unique&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;PdDistrict&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;dist_unique&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;count&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;ax2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Amount of Criminal Case in Selected District&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;crime_charts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dff_crime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2024/build-your-jupyter-dashboard-using-solara/images/004-1_5O_dyZhxuJMZNAMt3gw6rg.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;Since we do not need bidirectional communication (e.g., we do not need to receive events or data from our map), we use Folium to display the locations of the committed crimes on a map. If we do need bidirectional communication, we can use &lt;a href="https://ipyleaflet.readthedocs.io/"&gt;ipyleaflet&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Since we cannot display all the data on the map without crashing your browser, we limit it to a maximum of 50 points.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;folium&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;folium.plugins&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;crime_map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;latitude&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;37.77&lt;/span&gt;
    &lt;span class="n"&gt;longitude&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;122.42&lt;/span&gt;

    &lt;span class="n"&gt;sanfran_map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;folium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;longitude&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;zoom_start&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;incidents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;folium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plugins&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarkerCluster&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sanfran_map&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# loop through the dataframe and add each data point to the mark cluster&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;lat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;lng&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;folium&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Marker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lng&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="n"&gt;icon&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;popup&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;incidents&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# show map&lt;/span&gt;
    &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sanfran_map&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;crime_map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dff_crime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iloc&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="mi"&gt;50&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;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2024/build-your-jupyter-dashboard-using-solara/images/005-1_tTvZxrjpxsrsd7f1w55QjA.jpg" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;h2 id="making-our-first-reactive-visualization"&gt;Making our first reactive visualization&lt;/h2&gt;
&lt;p&gt;The above code works nicely, but if we want to explore different types of crimes, we need to modify and run all cells that determine our output manually. Would it not be much better to have a UI with controls determining the filtering and a view displaying the filtered data interactively?&lt;/p&gt;
&lt;p&gt;Let’s start by importing the solara package and creating three reactive variables.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;solara&lt;/span&gt;

&lt;span class="n"&gt;districts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;solara&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reactive&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Bayview&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Northern&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;categories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;solara&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reactive&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Vandalism&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Assault&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Robbery&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;limit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;solara&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reactive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A reactive variable is a container around a value (like an int, string, or list) that allows the UI to listen to changes automatically. Any change to &lt;code&gt;your_reactive_variable.value&lt;/code&gt; will be picked up by Solara components that use them so that they can automatically redraw or update themselves.&lt;/p&gt;
&lt;p&gt;Let us now create our first component (&lt;code&gt;View&lt;/code&gt;), which filters the data based on the reactive variables and shows the map and the charts. Solara supports the &lt;code&gt;display&lt;/code&gt; mechanism of Jupyter so that we can use our previously defined functions.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nd"&gt;@solara&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;component&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;View&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;dff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;crime_filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df_crime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;districts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;categories&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;row_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;row_count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;solara&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Only showing the first &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; of &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;row_count&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; crimes on map&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;crime_map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dff&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iloc&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt; &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;row_count&lt;/span&gt; &lt;span class="o"&gt;&amp;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;crime_charts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;solara&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;You filtered out all the data, no charts shown&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;View&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;figure&gt;
&lt;img alt="Our reactive visualization auto-updates when any reactive variable changes" src="https://jasongrout.github.io/medium-archive/pelican/posts/2024/build-your-jupyter-dashboard-using-solara/images/006-1_BhAMB3EetCG4IfnyuWuY1A.jpg" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Our reactive visualization auto-updates when any reactive variable changes&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Note that some UI parts (like the warning and the charts) are conditional. Solara will automatically find out what to add, remove, or update without you having to do this manually. Solara is declarative (similar to ReactJS) but also reactive. If we change the reactive variables, Solara will see those changes and notify the component instances that use its value.&lt;/p&gt;
&lt;p&gt;If we run the next lines of code in our notebook, our &lt;code&gt;View&lt;/code&gt; will automatically update.&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;limit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;70&lt;/span&gt;
&lt;span class="n"&gt;districts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Soutern&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Northern&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can now explore our data much faster since we don’t need to re-run the cells that depend on it.&lt;/p&gt;
&lt;p&gt;Solara’s reactive and declarative nature makes it scalable to much larger applications than regular ipywidgets, where keeping the UI in sync and adding, removing, and updating widgets is a manual and bug-prone process.&lt;/p&gt;
&lt;h2 id="adding-controls"&gt;Adding controls&lt;/h2&gt;
&lt;p&gt;We created a declarative and reactive mini app in our notebook, but we still need to manually modify the values by executing a code cell in our Notebook. Now, let us create a UI to control it. All Solara input components support reactive variables. This means that controlling a reactive variable using a UI element is often a one-liner.&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;solara&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SelectMultiple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;District&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;all_values&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;df_crime&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;PdDistrict&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unique&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tolist&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
    &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;districts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;figure&gt;
&lt;img alt="In one line of code we made our app filtering interactive by adding a dropdown" src="https://jasongrout.github.io/medium-archive/pelican/posts/2024/build-your-jupyter-dashboard-using-solara/images/007-1_oWB4IjwHBDQZHsf13zKG6w.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;In one line of code we made our app filtering interactive by adding a dropdown&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Whow, that was simple! We can now easily change the filter and see the results update. Lets do this for all our reactive variables, and put them into a single component.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nd"&gt;@solara&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;component&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Controls&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;solara&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SelectMultiple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;District&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;all_values&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;df_crime&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;PdDistrict&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unique&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tolist&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;districts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;solara&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SelectMultiple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Category&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;all_values&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;df_crime&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Category&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unique&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tolist&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;solara&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Maximum number of rows to show on map&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;solara&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SliderInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;Controls&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;figure&gt;
&lt;img alt="All controls for the filtering of our dataframe and visualization" src="https://jasongrout.github.io/medium-archive/pelican/posts/2024/build-your-jupyter-dashboard-using-solara/images/008-1_MhxvqxsURNH-1X9yr2La4g.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;All controls for the filtering of our dataframe and visualization&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Note that the reactive variables are bi-directional, meaning that if you change it in the UI elements, it gets reflected on the Python code!&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;# Note that we can read AND write reactive variables&lt;/span&gt;
&lt;span class="n"&gt;categories&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;categories&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Warrants&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="the-final-dashboard"&gt;The final dashboard&lt;/h2&gt;
&lt;p&gt;We now have two parts of our UI in separate cells. This can be an amazing experience when developing in a notebook, as it flows naturally in the data exploration process while writing your notebook.&lt;/p&gt;
&lt;p&gt;However, your end user will probably want something more coherent. The components we created are perfectly reusable, so we put them together in a single UI.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nd"&gt;@solara&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;component&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;solara&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sidebar&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;Controls&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;View&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;figure&gt;
&lt;img alt="Our end result" src="https://jasongrout.github.io/medium-archive/pelican/posts/2024/build-your-jupyter-dashboard-using-solara/images/009-1_5Ujq7HfB0YnX9yoAzFZmwA.jpg" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Our end result&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Finally, our dashboard is finished!&lt;/p&gt;
&lt;h2 id="conclusions"&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;Using Solara, you created an interactive dashboard within a Jupyter Notebook. Your Solara components are declarative, and when using reactive variables, they are also reactive. Whether you change reactive variables via code or the UI elements, your visualizations and maps update automatically.&lt;/p&gt;
&lt;p&gt;Your dashboard prototype now runs in your Jupyter Notebook environment, but we can only deploy it as an app. In our next article, we will focus on deploying our notebook without making any code changes. In our third tutorial, we will expand our dashboard with a few more components and create a more advanced layout.&lt;/p&gt;
&lt;p&gt;All documentation for Solara can be found at &lt;a href="https://solara.dev"&gt;https://solara.dev&lt;/a&gt;, the GitHub repo can be found at &lt;a href="https://github.com/widgetti/solara/"&gt;https://github.com/widgetti/solara/&lt;/a&gt; and feel free to join our &lt;a href="https://discord.solara.dev/"&gt;Discord&lt;/a&gt; for a chat.&lt;/p&gt;
</content><category term="dashboards"/><category term="visualization"/></entry><entry><title>And Voici!</title><link href="https://jasongrout.github.io/medium-archive/pelican/posts/2023/and-voici/" rel="alternate"/><published>2023-12-06T15:21:00+00:00</published><updated>2023-12-06T15:21:00+00:00</updated><author><name>Duc Trung Le</name></author><id>tag:jasongrout.github.io,2023-12-06:/medium-archive/pelican/posts/2023/and-voici/</id><summary type="html">&lt;p&gt;Scaling Jupyter dashboards up to the millions.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2023/and-voici/images/001-1_Tjh9IaZrdJhTQzxyIOgI8Q.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;Voici (meaning “here is” in French) is a novel project reshaping Jupyter-based interactive dashboards by combining &lt;a href="/posts/2019/and-voila/"&gt;Voilà&lt;/a&gt; and &lt;a href="/posts/2021/jupyterlite-jupyter-webassembly-python/"&gt;JupyterLite&lt;/a&gt; features. It facilitates the creation of dynamic, in-browser environments for data visualization and exploration.&lt;/p&gt;
&lt;p&gt;Built upon the foundations of Voilà, Voici inherits the ability to convert any Jupyter notebook into a standalone user-friendly dashboard. While the simplicity and extensibility of Voilà are kept intact, &lt;strong&gt;Voici adopts the in-browser execution model of JupyterLite, replacing the client-server approach&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Dashboards generated by Voici are simply a collection of static files. Deploying and scaling such dashboards is straightforward since there is no need to allocate computational resources in the backend.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Voici dashboards are extraordinarily scalable compared to their “Voilà” counterparts, since they don’t require a container per user session.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Voilà and Voici, as their name suggests, share a lot of commonalities like the CLI, the configuration options, and the templating system. The difference in their execution model results in a distinction: Voilà can hide the source code from the browser, displaying only the rendered dashboard, whereas Voici exposes the entire notebook content to the front end.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="From a notebook to a Voici dashboard" src="https://jasongrout.github.io/medium-archive/pelican/posts/2023/and-voici/images/002-0_pW-uDn20xeFuu6ce.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;&lt;em&gt;From a notebook to a Voici dashboard&lt;/em&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="installation-and-first-time-use"&gt;Installation and first-time use&lt;/h2&gt;
&lt;p&gt;You can install Voici using pip:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pip&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;voici
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Or using conda/mamba:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mamba&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;voici&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;conda-forge
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Upon installation, the Voici command-line utility becomes available and &lt;strong&gt;can be used as a drop-in replacement for the &lt;em&gt;voila&lt;/em&gt; command&lt;/strong&gt;. For example, you can generate static dashboards from a notebook or a directory of notebooks like this:&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;# Build a single dashboard&lt;/span&gt;
voici&lt;span class="w"&gt; &lt;/span&gt;my-notebook.ipynb
&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;# Build a directory of notebooks&lt;/span&gt;
voici&lt;span class="w"&gt; &lt;/span&gt;notebooks/
&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;# Build a dashboard with a dark theme and voila-gridstack template&lt;/span&gt;
voici&lt;span class="w"&gt; &lt;/span&gt;my-notebook.ipynb&lt;span class="w"&gt; &lt;/span&gt;--template&lt;span class="w"&gt; &lt;/span&gt;gridstack&lt;span class="w"&gt; &lt;/span&gt;--theme&lt;span class="w"&gt; &lt;/span&gt;dark
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once the dashboards are built in the &lt;em&gt;_output&lt;/em&gt; directory, you can simply serve the static web page with your favorite web server. For example, using CPython’s simple HTTP server:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;python&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;http.server&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;_output
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;figure&gt;
&lt;img alt="A Voici dashboard using the dark theme" src="https://jasongrout.github.io/medium-archive/pelican/posts/2023/and-voici/images/003-0_26EQ9I6L6MnwIaND.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;&lt;a href="https://trungleduc.github.io/voici-stock-dashboard/voici/render/dashboard.html"&gt;&lt;em&gt;A Voici dashboard&lt;/em&gt;&lt;/a&gt; &lt;em&gt;using the dark theme&lt;/em&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;For the configurations of the themes, templates, or the tree page, you can refer to the &lt;a href="https://voila.readthedocs.io/en/stable/customize.html"&gt;Voilà documentation&lt;/a&gt; for available options. The Voici-specific configurations can be found in the &lt;a href="https://voici.readthedocs.io"&gt;Voici documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="deploy-voici-dashboard"&gt;Deploy Voici dashboard&lt;/h2&gt;
&lt;p&gt;Besides the static site hosting services, it is also possible to deploy Voici dashboards to GitHub Pages directly from your repository or to embed them into Sphinx documentation.&lt;/p&gt;
&lt;h3 id="publishing-voici-dashboards-on-github-pages"&gt;Publishing Voici dashboards on GitHub Pages&lt;/h3&gt;
&lt;p&gt;Creating your deployment on GitHub Pages is straightforward with the help of a &lt;a href="https://github.com/voila-dashboards/voici-demo"&gt;template repository&lt;/a&gt; available on GitHub. You can follow the instructions from the following video:&lt;/p&gt;
&lt;iframe src="https://www.youtube-nocookie.com/embed/ejtACmuecQg" title="Voici Dashboard Deployed on Github Pages" width="560" height="315" style="aspect-ratio: 560 / 315" loading="lazy" allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;The dashboard will be built by the CI action and published on the corresponding GitHub page of your repository.&lt;/p&gt;
&lt;h3 id="embedding-voici-dashboards-in-sphinx-documentation"&gt;Embedding Voici dashboards in Sphinx documentation&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;jupyterlite-sphinx&lt;/em&gt; is a Python package that allows embedding Jupyterlite in Sphinx documentation using simple directives. It is used in the documentation of major projects like &lt;em&gt;scikit-image&lt;/em&gt; or &lt;em&gt;ipywidgets&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In addition to JupyterLite applications, this package also supports embedding Voici dashboards with the &lt;a href="https://jupyterlite-sphinx.readthedocs.io/en/latest/directives/voici.html"&gt;voici directive&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;voici&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;my_notebook&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ipynb&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="ss"&gt;:height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="n"&gt;px&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="ss"&gt;:prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;Try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;Voici&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="ss"&gt;:prompt_color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#dc3545&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With this directive, the Voici dashboard will be generated automatically with the Sphinx documentation, and the dashboard will be loaded as per user request.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="A Voici dashboard embedded in Sphinx documentation" src="https://jasongrout.github.io/medium-archive/pelican/posts/2023/and-voici/images/004-0_uwgSS42KAo1EkCvF.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;A Voici dashboard embedded in Sphinx documentation&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="voici-gallery"&gt;Voici gallery&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://voila-dashboards.github.io/voici-gallery/"&gt;Voici gallery&lt;/a&gt; is a collection of dashboards built with Voici, it aims to provide a source of inspiration for crafting complex dashboards entirely based on the Jupyter ecosystem.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Voici Gallery home page" src="https://jasongrout.github.io/medium-archive/pelican/posts/2023/and-voici/images/005-0_K5TYc8RPlRPBKcdU.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Voici Gallery home page&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;If you’ve created an interesting dashboard and would like to share it with a wider audience, don’t hesitate to submit a pull request &lt;a href="https://github.com/voila-dashboards/voici-gallery"&gt;here&lt;/a&gt; to have it included in the list of examples!&lt;/p&gt;
&lt;h2 id="future-development"&gt;Future development&lt;/h2&gt;
&lt;p&gt;Voici is rapidly evolving, with many improvements already in the works such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Better integration with JupyterLab and JupyterLite to preview and generate Voici dashboards from their user interface.&lt;/li&gt;
&lt;li&gt;Provide more user-friendly tools to easily deploy Voici dashboards to other platforms like GitLab and HuggingFace,…&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;User feedback from the community also plays a big role in the project roadmap. Explore Voici and share your thoughts with us using the &lt;a href="https://github.com/voila-dashboards/voici/issues"&gt;project’s GitHub issues&lt;/a&gt;!&lt;/p&gt;
&lt;h2 id="about-the-authors"&gt;About the authors&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2023/and-voici/images/006-0_FA4jYIdu6lJ4-U4p.jpg" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://twitter.com/martinRenou"&gt;Martin Renou&lt;/a&gt; is a Technical Director at &lt;a href="https://quantstack.net/"&gt;&lt;strong&gt;QuantStack&lt;/strong&gt;&lt;/a&gt; and a maintainer of &lt;a href="https://jupyter.org/"&gt;&lt;strong&gt;Project Jupyter&lt;/strong&gt;&lt;/a&gt;. Among other projects Martin is a core team member of the ipywidgets project and maintains many Jupyter widget packages such as &lt;a href="https://github.com/jupyter-widgets/ipyleaflet"&gt;ipyleaflet&lt;/a&gt;, &lt;a href="https://github.com/bloomberg/ipydatagrid"&gt;ipydatagrid&lt;/a&gt;, &lt;a href="https://github.com/QuantStack/ipygany"&gt;ipygany&lt;/a&gt;, &lt;a href="https://github.com/martinRenou/ipycanvas"&gt;ipycanvas&lt;/a&gt;, and &lt;a href="https://github.com/bqplot/bqplot"&gt;bqplot&lt;/a&gt;. He is a co-creator of the &lt;a href="https://github.com/voila-dashboards/voila/"&gt;Voilà&lt;/a&gt; dashboarding system, and the &lt;a href="https://github.com/jupyter-xeus/xeus-python"&gt;xeus-python&lt;/a&gt; kernel.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2023/and-voici/images/007-0_TOhdhVrxFO17XsXl.jpg" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/trungleduc"&gt;Le Duc Trung&lt;/a&gt; is a Scientific Software Developer at QuantStack. He works on several projects within the Jupyter ecosystem, from the main projects like JupyterLab, Voilà, and ipywidgets to various JupyterLab extensions and widgets.&lt;/p&gt;
</content><category term="dashboards"/></entry><entry><title>Voilà 0.5.0 : Homecoming</title><link href="https://jasongrout.github.io/medium-archive/pelican/posts/2023/voila-0-5-0-homecoming/" rel="alternate"/><published>2023-09-25T14:54:00+00:00</published><updated>2023-09-25T14:54:00+00:00</updated><author><name>Duc Trung Le</name></author><id>tag:jasongrout.github.io,2023-09-25:/medium-archive/pelican/posts/2023/voila-0-5-0-homecoming/</id><summary type="html">&lt;p&gt;Voila 0.5.0 is here!&lt;/p&gt;
</summary><content type="html">&lt;h2 id="voila-050-homecoming"&gt;Voilà &lt;strong&gt;0.5.0:&lt;/strong&gt; Homecoming&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2023/voila-0-5-0-homecoming/images/001-1_Oqkkz64NWqTFoS45sfprGQ.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 and dashboards. It provides a simple way for Jupyter users to share their work. For a detailed introduction to Jupyter’s Voilà subproject, you can check out this earlier &lt;a href="/posts/2019/and-voila/"&gt;blog post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Up until the previous version, Voilà relied on custom JavaScript code to load extension assets and handle kernel connection. However, this approach had drawbacks since it only supported the now outdated Jupyter Notebook 6 extensions.&lt;/p&gt;
&lt;p&gt;Following the launch of &lt;a href="/posts/2023/announcing-jupyter-notebook-7/"&gt;Jupyter Notebook 7&lt;/a&gt;, it is now Voilà’s turn to join the JupyterLab family. In Version 0.5.0, the front-end of Voilà has been rebuilt from scratch using JupyterLab 4.0 components, just like in the case of Notebook 7. A JupyterLab plugin-based application replaces the current custom extension loader approach. This transition enables Voilà to leverage all the latest features and enhancements available upstream.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="new-features-in-voila-050"&gt;New features in Voilà 0.5.0&lt;/h2&gt;
&lt;h3 id="extension-loading-system"&gt;Extension loading system&lt;/h3&gt;
&lt;p&gt;As of Version 0.5.0, Voilà uses the same prebuilt extension system as JupyterLab. The extension assets are loaded from local paths rather than relying on a CDN, resulting in a significant enhancement to Voilà’s extension compatibility with the rest of the JupyterLab ecosystem. This change also avoids making requests for external services. Additionally, users can now develop extensions for Voilà using the same approach as for JupyterLab extensions.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="A Voila dashboard with top bar extension and custom JupyterLab theme." src="https://jasongrout.github.io/medium-archive/pelican/posts/2023/voila-0-5-0-homecoming/images/002-1_W1dHdjWC0CYoLjCWXXxU2w.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;A Voila dashboard with &lt;a href="https://github.com/voila-dashboards/voila-topbar"&gt;top bar extension&lt;/a&gt; and &lt;a href="https://github.com/timkpaine/jupyterlab_miami_nights"&gt;custom JupyterLab theme&lt;/a&gt;.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id="mimetype-rendering-mechanism"&gt;Mimetype rendering mechanism&lt;/h3&gt;
&lt;p&gt;In 0.5.0, the logic for rendering cell outputs containing mimetypes has been revised, moving away from relying on &lt;code&gt;nbconvert&lt;/code&gt; and instead depending on JupyterLab mimetype renderers. This change adds support for a wide range of custom JupyterLab renderers such as &lt;code&gt;jupyterlab-fasta&lt;/code&gt;, &lt;code&gt;vega&lt;/code&gt;, &lt;code&gt;jupyterlab-geojson&lt;/code&gt;, etc.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Rendering mimetypes data in Voila" src="https://jasongrout.github.io/medium-archive/pelican/posts/2023/voila-0-5-0-homecoming/images/003-1_WWRmwTs5v_U8HL27JzY7Uw.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Rendering mimetypes data in Voila&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id="new-tree-page"&gt;New tree page&lt;/h3&gt;
&lt;p&gt;The default tree page in Voilà has transitioned into a JupyterLab-based application incorporating the file browser widget. While the Jinja-based tree page remains available, users must opt for it using either the &lt;code&gt;--classic-tree&lt;/code&gt; CLI option or by appending &lt;code&gt;?classic-tree=True&lt;/code&gt;to the query string.&lt;/p&gt;
&lt;p&gt;The new tree page in Voilà supports JupyterLab custom themes, whereas the classic tree page is limited to light and dark themes.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="New tree page with a custom theme." src="https://jasongrout.github.io/medium-archive/pelican/posts/2023/voila-0-5-0-homecoming/images/004-1_Yp5wC6yCRbCNejKtKZV8Ww.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;New tree page with a &lt;a href="https://github.com/martinRenou/jupyterlab-night"&gt;custom theme&lt;/a&gt;.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id="token-based-authentication-system"&gt;Token-based authentication system&lt;/h3&gt;
&lt;p&gt;Depending on the identity provider of &lt;code&gt;jupyter-server&lt;/code&gt; 2, Voilà now supports token authentication but is disabled by default.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;To start Voilà with auto-generated token:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;voila&lt;span class="w"&gt; &lt;/span&gt;--token&lt;span class="w"&gt; &lt;/span&gt;...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;To start Voilà with a personalized token:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;voila&lt;span class="w"&gt; &lt;/span&gt;--token&lt;span class="o"&gt;=&lt;/span&gt;my-secret-token&lt;span class="w"&gt; &lt;/span&gt;...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id="installing-voila"&gt;Installing Voilà&lt;/h2&gt;
&lt;p&gt;Voila is available on both &lt;code&gt;PyPI&lt;/code&gt; and &lt;code&gt;conda-forge&lt;/code&gt;:&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;# Install with pip&lt;/span&gt;
pip&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;voila

&lt;span class="c1"&gt;# Install with mamba&lt;/span&gt;
mamba&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;voila
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can try Voilà online using &lt;a href="https://voila-dashboards-voila-huggingface.hf.space/"&gt;this link&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="acknowledgments"&gt;Acknowledgments&lt;/h2&gt;
&lt;p&gt;The contributions to Voilà by &lt;a href="https://github.com/QuantStack"&gt;&lt;strong&gt;QuantStack&lt;/strong&gt;&lt;/a&gt; are supported 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-contributors"&gt;About the Contributors&lt;/h2&gt;
&lt;p&gt;Voilà is an official Jupyter subproject, it has resulted from the collective efforts of &lt;a href="https://github.com/voila-dashboards/voila/graphs/contributors"&gt;numerous contributors&lt;/a&gt;. Below, we highlight the primary contributors for this release:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2023/voila-0-5-0-homecoming/images/005-0_x5BSQzmN_DVAFLc5.webp" alt="" loading="lazy" data-body-image=""&gt;&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. Maintainer and contributor of JupyterLab, Jupyter Notebook, JupyterLite, Voilà, and projects within the Jupyter ecosystem.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2023/voila-0-5-0-homecoming/images/006-0_jOsGiBpJ5Qt2t15C.jpg" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://twitter.com/martinRenou"&gt;&lt;strong&gt;Martin Renou&lt;/strong&gt;&lt;/a&gt; is a Project Director at &lt;a href="https://quantstack.net/"&gt;QuantStack&lt;/a&gt; and a Jupyter Distinguished Contributor. Martin works on a variety of projects, from &lt;a href="https://github.com/QuantStack/xtensor"&gt;xtensor&lt;/a&gt; and &lt;a href="https://github.com/QuantStack/xeus-python/"&gt;xeus-python&lt;/a&gt; in C++ to &lt;a href="https://github.com/jupyter-widgets/ipywidgets"&gt;ipywidgets&lt;/a&gt;, &lt;a href="https://github.com/jupyter-widgets/ipyleaflet"&gt;ipyleaflet&lt;/a&gt; and &lt;a href="https://github.com/bqplot/bqplot"&gt;bqplot&lt;/a&gt; in Python and TypeScript.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2023/voila-0-5-0-homecoming/images/007-1_uSLpGo9pf1l4HIaxPFYysg.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/trungleduc"&gt;&lt;strong&gt;Le Duc Trung&lt;/strong&gt;&lt;/a&gt; is a Scientific Software Developer at QuantStack. He works on several projects within the Jupyter ecosystem, from the main projects like JupyterLab, Voilà, and ipywidgets to various JupyterLab extensions and widgets.&lt;/p&gt;
</content><category term="dashboards"/><category term="Voilà"/></entry><entry><title>Need for Speed: Voilà edition</title><link href="https://jasongrout.github.io/medium-archive/pelican/posts/2021/need-for-speed-voila-edition/" rel="alternate"/><published>2021-12-10T14:52:00+00:00</published><updated>2021-12-10T14:52:00+00:00</updated><author><name>Duc Trung Le</name></author><id>tag:jasongrout.github.io,2021-12-10:/medium-archive/pelican/posts/2021/need-for-speed-voila-edition/</id><summary type="html">&lt;p&gt;TL;DR: Voilà 0.3.0 is now available!&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2021/need-for-speed-voila-edition/images/001-1_gSWxQGu60SG5DdH8MIzCjw.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="/posts/2019/and-voila/"&gt;Voilà&lt;/a&gt; turns Jupyter notebooks into standalone applications without requiring any modification to the content. You want to share your content with non-technical readers? Just call Voilà with the notebook to turn it into a deployable web application. The simplicity of Voilà comes at a cost: &lt;em&gt;the page load&lt;/em&gt; &lt;em&gt;time.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We set ourselves to fix this Achilles’ heel while preserving the ease-of-use of Voilà. Today we are pleased to announce the release of Voilà 0.3.0, with a focus on performance.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="motivation"&gt;Motivation&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Page load time has a critical impact on user experience of a website.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;According to &lt;a href="https://blog.kissmetrics.com/wp-content/uploads/2011/04/loading-time.pdf"&gt;Kissmetrics&lt;/a&gt;, nearly half of web users expect a site to load in 2 seconds or less, and they tend to abandon a site that is not loaded within 3 seconds.&lt;/p&gt;
&lt;p&gt;In the case of Voilà, a simple dashboard takes around one second to render and more complicated dashboards (involving libraries import, data fetching, and widgets) can easily push users out of their comfort zone. Several efforts have been made to improve the situation, from adding an execution progress indicator to enhancing the rendering technique. The load time of a medium-to-high complexity notebook has not been cut down to a desirable range yet. That is why in the 0.3.0 version, we aimed at addressing the main bottleneck of Voilà: &lt;em&gt;the execution of notebook&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="preheated-kernels"&gt;Preheated kernels&lt;/h2&gt;
&lt;p&gt;Based upon an excellent idea of the &lt;a href="https://github.com/voila-dashboards/hotpot_km"&gt;hotpot_km&lt;/a&gt; project about the pooling hot-loaded Jupyter kernels, we implemented a new solution called “preheated kernels” to diminish the waiting time for starting a new python kernel and for executing the requested notebook.&lt;/p&gt;
&lt;p&gt;Preheated kernels can be activated just by setting the&lt;code&gt;preheat_kernel&lt;/code&gt; option to &lt;code&gt;True&lt;/code&gt;in the Voilà command line or configuration file. For example, this command will activate preheated kernels feature for the &lt;code&gt;voila.ipynb&lt;/code&gt; notebook with a pool of five kernels:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;voila voila.ipynb --preheat_kernel=True --pool_size=5
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;figure&gt;
&lt;img alt="Speed comparison between Voila 0.3.0 and 0.2.x" src="https://jasongrout.github.io/medium-archive/pelican/posts/2021/need-for-speed-voila-edition/images/002-1_djVMI5ujhEq6xVbYJNzuuA.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Speed comparison between Voilà 0.3.0 with preheated kernel and 0.2.16&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Behind the scene, the two following actions are performed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For each notebook, a queue of kernels is created and the notebook is executed in every kernel. When a new client requests a kernel, the oldest preheated kernel of the pool is used and another kernel is started asynchronously to refill the pool.&lt;/li&gt;
&lt;li&gt;The rendered HTML for the notebook is produced in advance for each preheated kernel and directly served to the client upon connection.&lt;/li&gt;
&lt;li&gt;If the kernel pool is empty, Voilà will fall back to starting a new kernel and render the notebook as usual. The advanced configurations of preheated kernels are detailed in &lt;a href="https://voila.readthedocs.io/en/latest/customize.html#preheated-kernels"&gt;Voilà’s official documentation&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="partially-pre-render-notebook"&gt;Partially pre-render notebook&lt;/h2&gt;
&lt;p&gt;To benefit from the acceleration of preheated kernels mode, the notebooks need to be pre-rendered before users connect to Voilà. But in many real-world applications, the notebook requires user-specific data, which makes pre-rendering impossible. To overcome this limit, Voilà offers a feature to handle the most used method for providing user data: the URL query string.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="In preheated kernels mode, Voilà executed the first 4 cells before waiting for the query string from the user." src="https://jasongrout.github.io/medium-archive/pelican/posts/2021/need-for-speed-voila-edition/images/003-1_Gwq82pb0qAInlPUJm_-JYA.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;In preheated kernels mode, Voilà executed the first 4 cells before waiting for the query string from the user.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In normal mode, Voilà users can get the query string at run time through the &lt;code&gt;QUERY_STRING&lt;/code&gt; environment variable:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;os&lt;/span&gt;
&lt;span class="n"&gt;query_string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;QUERY_STRING&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In preheated kernels mode, users can simply replace the &lt;code&gt;os.getenv&lt;/code&gt; call with the helper &lt;code&gt;get_query_string&lt;/code&gt; from &lt;code&gt;voila.utils&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;voila.utils&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get_query_string&lt;/span&gt;
&lt;span class="n"&gt;query_string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_query_string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;get_query_string&lt;/code&gt; will pause the execution of the notebook by the preheated kernel at this cell and wait for an actual user to connect to Voilà, then &lt;code&gt;get_query_string&lt;/code&gt; will return the URL query string and continue the execution of the remaining cells.&lt;/p&gt;
&lt;p&gt;To maximize the benefits of preheated kernels, the user-independent cells should be placed before the &lt;code&gt;get_query_string&lt;/code&gt;call.&lt;/p&gt;
&lt;h2 id="whats-next"&gt;What’s next?&lt;/h2&gt;
&lt;p&gt;There is more in the works to improve Voilà’s performances. Beyond kernel hot pooling, we will improve the performance of rendering Jupyter widgets in the front-end. Several of these improvements will be enabled with the upcoming 8.0 release of ipywidgets, and more optimizations are in the works.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="acknowledgments"&gt;Acknowledgments&lt;/h2&gt;
&lt;p&gt;We would like to thank &lt;a href="https://github.com/vidartf"&gt;Vidar Tonaas Fauske&lt;/a&gt; and &lt;a href="https://github.com/maartenbreddels"&gt;Maarten Breddels&lt;/a&gt; for the prior art on the &lt;a href="https://github.com/voila-dashboards/hotpot_km"&gt;hotpot_km&lt;/a&gt; project, which was an inspiration for this work in core Voilà.&lt;/p&gt;
&lt;h2 id="about-the-author"&gt;About the author&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/trungleduc"&gt;Duc Trung Le&lt;/a&gt; is a Scientific Software Developer at &lt;a href="https://twitter.com/QuantStack"&gt;QuantStack&lt;/a&gt;. He works on several projects within the Jupyter ecosystem, from the main projects like JupyterLab, Voilà, ipywidgets to Jupyter extensions and widgets.&lt;/p&gt;
</content><category term="dashboards"/><category term="Voilà"/></entry><entry><title>Dashboarding with JupyterLab 3</title><link href="https://jasongrout.github.io/medium-archive/pelican/posts/2021/dashboarding-with-jupyterlab-3/" rel="alternate"/><published>2021-01-08T10:25:00+00:00</published><updated>2021-01-08T11:15:00+00:00</updated><author><name>Carlos Herrero</name></author><id>tag:jasongrout.github.io,2021-01-08:/medium-archive/pelican/posts/2021/dashboarding-with-jupyterlab-3/</id><summary type="html">&lt;p&gt;Project Jupyter offers a complete suite of open-source tools for the scientific computing community, reaching from the exploratory phase…&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Project Jupyter offers a complete suite of open-source tools for the scientific computing community, reaching from the exploratory phase of a project to the presentation of the results. In this last but not least phase is where Voilà takes place, &lt;strong&gt;turning a technical document such as Notebook into an interactive presentation or a stand-alone web app ready to be shared with non-technical readers&lt;/strong&gt;. You can learn more about Voilà in &lt;a href="/posts/2019/and-voila/"&gt;this blog post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Voilà is an easy-to-use command-line tool that shines in its simplicity and flexibility. All its versatility comes from a custom template system built upon Jinja templates that allows everyone to create a custom UI to share Jupyter Notebooks. Examples of the versatility provided for the template system are &lt;a href="/posts/2019/a-slideshow-template-for-voila-apps/"&gt;&lt;em&gt;voila-reveal&lt;/em&gt;&lt;/a&gt; and &lt;a href="/posts/2019/a-slideshow-template-for-voila-apps/"&gt;&lt;em&gt;voila-gridstack&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Voila-gridstack&lt;/em&gt; is a Voilà template started by &lt;a href="https://github.com/btel"&gt;Bartosz Telenczuk&lt;/a&gt; to &lt;strong&gt;turn notebooks into dashboards&lt;/strong&gt; following the specification introduced by the legacy &lt;em&gt;jupyter-dashboards&lt;/em&gt; project. The idea behind is to be able to change the layout of the cells to re-configure your dashboards using drag-and-drop. Once you have your desired layout, its configuration stays in the metadata of the notebook. This makes it simple to carry around or share the notebook and its layout configuration.&lt;/p&gt;
&lt;p&gt;With the release of JupyterLab 3.0, we wanted to update the &lt;em&gt;voila-gridstack&lt;/em&gt; template by adding an editor for JupyterLab.&lt;/p&gt;
&lt;h2 id="configure-your-layout"&gt;Configure your layout&lt;/h2&gt;
&lt;p&gt;The first way to open the &lt;em&gt;voila-gridstack&lt;/em&gt; editor is by right-clicking on the notebook and selecting open with “Voilà Gridstack”. The editor is itself a JupyterLab Document Widget, which can be seen as another view of the same notebook document. The editor can also be launched from the classic notebook with a toolbar button.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Opening JupyterLab-Gridstack" src="https://jasongrout.github.io/medium-archive/pelican/posts/2021/dashboarding-with-jupyterlab-3/images/001-1_m3zuJtMenNyGL-0R2nz7Cg.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Opening JupyterLab-Gridstack&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Once the editor is open, every cell is decorated with a toolbar as a drag-and-drop handle and a button to remove the cell from the dashboard. When removing a cell, it is just marked as hidden in the metadata but it is not deleted from the notebook file. Besides, handles are provided for resizing cells in the layout.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Configuring your layout" src="https://jasongrout.github.io/medium-archive/pelican/posts/2021/dashboarding-with-jupyterlab-3/images/002-1_u0AnafiS2HtXhCiCMg25cA.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Configuring your layout&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;When opening the editor for the first time in a new notebook, the metadata of the notebook is modified to follow &lt;em&gt;jupyter-dashboards&lt;/em&gt;’ specification. By default, you will see an empty editor. To add new cells just drag them from the notebook view. It is not possible to add cells from another notebook.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Adding new cells" src="https://jasongrout.github.io/medium-archive/pelican/posts/2021/dashboarding-with-jupyterlab-3/images/003-1_t4EW3oCIrt5FaMXUyjYPFw.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Adding new cells&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Finally, you can save the layout into the metadata of the notebook by clicking the “save” button or with the &lt;code&gt;ctrl+s&lt;/code&gt; shortcut and then it’s time to hit the render button and Voilà! You will see your layout as a stand-alone web app.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Voilà! Your stand-alone web app" src="https://jasongrout.github.io/medium-archive/pelican/posts/2021/dashboarding-with-jupyterlab-3/images/004-1_y6-MX2tjbBavUr3GHFDnIw.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Voilà! Your stand-alone web app&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="try-it-online"&gt;Try it online!&lt;/h2&gt;
&lt;p&gt;You can try the &lt;a href="https://github.com/voila-dashboards/voila-gridstack"&gt;j&lt;em&gt;upyterlab-gridstack&lt;/em&gt;&lt;/a&gt; extension online without installing anything by just clicking on the following image:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mybinder.org/v2/gh/voila-dashboards/voila-gridstack/stable?urlpath=lab/tree/examples"&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2021/dashboarding-with-jupyterlab-3/images/005-1_JsZ-IeoC7225JzNIHR1acA.webp" alt="https://mybinder.org/v2/gh/voila-dashboards/voila-gridstack/stable?urlpath=/voila/tree/examples/scotch_dashboard.ipynb" loading="lazy" data-body-image=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="installation"&gt;Installation&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Voila-gridstack&lt;/em&gt; is available as a conda package, and you can easily install it by typing the following command in a conda environment:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mamba install -c conda-forge jupyterlab voila-gridstack
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="acknowledgements"&gt;Acknowledgements&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;The example notebook used as an example in this post was one of the example notebooks of the legacy Jupyter dashboards project.&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/CarlosHerreroB"&gt;Carlos Herrero&lt;/a&gt; is a Computer Engineer passionate about AI and its applications to robotics. Currently working at QuantStack helping to develop Open Source projects.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Carlos Herrero" src="https://jasongrout.github.io/medium-archive/pelican/posts/2021/dashboarding-with-jupyterlab-3/images/006-1_y3NheY8vpXLUDnh7Cpnruw.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Carlos Herrero&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;a href="https://twitter.com/jtpio"&gt;Jeremy Tuloup&lt;/a&gt; is a Scientific Software Developer at QuantStack, working on JupyterLab, Voilà, and various other projects within the Jupyter ecosystem.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Jeremy Tuloup" src="https://jasongrout.github.io/medium-archive/pelican/posts/2021/dashboarding-with-jupyterlab-3/images/007-1_TSPSpj2D0UODcXXAgbHOXg.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Jeremy Tuloup&lt;/figcaption&gt;
&lt;/figure&gt;
</content><category term="dashboards"/><category term="JupyterLab"/></entry><entry><title>Report on the Jupyter Community Workshop on Dashboarding</title><link href="https://jasongrout.github.io/medium-archive/pelican/posts/2020/report-on-the-jupyter-community-workshop-on/" rel="alternate"/><published>2020-02-14T21:06:00+00:00</published><updated>2020-02-14T21:06:00+00:00</updated><author><name>Sylvain Corlay</name></author><id>tag:jasongrout.github.io,2020-02-14:/medium-archive/pelican/posts/2020/report-on-the-jupyter-community-workshop-on/</id><summary type="html">&lt;p&gt;This report is long overdue! From June 3rd to June 6th 2019, thirty-five developers from the Jupyter community met in Paris for a…&lt;/p&gt;
</summary><content type="html">&lt;p&gt;From June 3rd to June 6th 2019, thirty-five developers from the Jupyter community met in Paris for a four-day workshop on dashboarding with Project Jupyter.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Attendees to the Jupyter Community Workshop on Kernels (Photo credit to Lindsey Heagy)" src="https://jasongrout.github.io/medium-archive/pelican/posts/2020/report-on-the-jupyter-community-workshop-on/images/001-1_e8gJ4j2hCn4XMPagp6etOA.jpeg" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Attendees to the Jupyter Community Workshop on Kernels (Photo credit to Lindsey Heagy)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;For four days, attendees worked full time on the Jupyter project, including hacking sessions and discussions on improvements to Jupyter components and new development. We were lucky to count a large number of core developers to the project in the group.&lt;/p&gt;
&lt;p&gt;Beyond the hacking sessions, each day was concluded with a series of presentations and demos of the progress made during the workshop. In partnership with the &lt;a href="https://twitter.com/pydataparis"&gt;PyData Paris&lt;/a&gt; team, we had a special installment of the PyData Paris Meetup with&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;an invited presentation by &lt;a href="https://twitter.com/egouillart"&gt;Emmanuelle Gouillart&lt;/a&gt; on &lt;a href="https://plot.ly/dash/"&gt;Plotly Dash&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;a series of lightning talks by attendees of the workshop on their achievements, including a talk by &lt;a href="https://github.com/philippjfr"&gt;Philip Rudiger&lt;/a&gt; on the first release of &lt;a href="https://github.com/holoviz/panel"&gt;Panel&lt;/a&gt;, and an announcement of the first releases of &lt;a href="https://github.com/voila-dashboards/voila"&gt;Voilà&lt;/a&gt; and the Voilà Gallery.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We ended the week with a social evening at the &lt;a href="https://twitter.com/QuantStack"&gt;QuantStack&lt;/a&gt; offices in Paris.&lt;/p&gt;
&lt;h2 id="why-a-workshop-on-jupyter-dashboarding-with-jupyter"&gt;Why a workshop on Jupyter Dashboarding with Jupyter?&lt;/h2&gt;
&lt;p&gt;The Jupyter ecosystem is used extensively in scientific computing both in academia and industry, and a rich ecosystem of data visualization tools has been developed around the Jupyter widgets frameworks, from geographical data visualization to protein folding simulation.&lt;/p&gt;
&lt;p&gt;However, the Jupyter ecosystem still did not provide a means for developers to transition from notebooks to stand-alone web applications that can be accessed by multiple users.&lt;/p&gt;
&lt;p&gt;This has been a longstanding request from the community: provide better tools built upon the Jupyter stack to share results with students, peers, or the general public.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;These are the challenges that we decided to tackle during that week. The workshop was attended by many Jupyter core developers.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="highlights-of-the-week"&gt;Highlights of the week&lt;/h2&gt;
&lt;p&gt;Many of the developers spent the week working on the Voilà and Panel projects. Both projects had their first public releases during that week (see the first public announcement of &lt;a href="https://medium.com/@philipp.jfr/panel-announcement-2107c2b15f52"&gt;Panel&lt;/a&gt; and &lt;a href="/posts/2019/and-voila/"&gt;Voilà&lt;/a&gt;).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;During this week, a team of participants including Yuvi Panda, Pascal Bugnion, and Jeremy Tuloup iterated on the first version of the Voilà gallery. Several first-time contributors to the widget framework authored example dashboards for the gallery, showcasing their existing work. Yuvi also produced the first deployment scenarii for Voilà on Heruku.&lt;/li&gt;
&lt;li&gt;Cheryl Quah, from Bloomberg MC-ed a panel on dashboarding in the Jupyter ecosystem, including lots of questions and comparisons with Dash.&lt;/li&gt;
&lt;li&gt;Philip Rudigger started working on a Bokeh/ipywidgets integration for better interoperability between the two frameworks.&lt;/li&gt;
&lt;li&gt;Other contributors iterated on creating new Voilà templates, such as voila-vuetify, adding the ability to position Jupyter widgets and outputs in arbitrary location in the dashboard template. Grant Nestor created visual mockups for a UI for creating dashboard layouts in JupyterLab. Grant also helped iterating on logos for the project, and gave a presentation on dynamically loading JavaScript modules in the browser.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="acknowledgments"&gt;Acknowledgments&lt;/h2&gt;
&lt;p&gt;This event would not have been possible without the generous support provided by &lt;a href="https://www.techatbloomberg.com/"&gt;&lt;strong&gt;Bloomberg&lt;/strong&gt;&lt;/a&gt;, who made this workshop series possible&lt;/p&gt;
&lt;p&gt;We are grateful to &lt;a href="https://twitter.com/SG_CIB"&gt;&lt;strong&gt;Société Générale&lt;/strong&gt;&lt;/a&gt; for funding the catering for the workshop.&lt;/p&gt;
&lt;p&gt;The hosting of the workshop at &lt;a href="https://cri-paris.org/"&gt;CRI&lt;/a&gt; was paid for by &lt;a href="https://twitter.com/QuantStack"&gt;&lt;strong&gt;QuantStack&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The public meetup was organized in partnership with the &lt;a href="https://twitter.com/pydataparis"&gt;&lt;strong&gt;PyData Paris&lt;/strong&gt;&lt;/a&gt; team.&lt;/p&gt;
&lt;p&gt;Finally, we especially thank &lt;a href="https://twitter.com/ruv7?lang=en"&gt;&lt;strong&gt;Ana Ruvalcaba&lt;/strong&gt;&lt;/a&gt; from Project Jupyter for her incredible work on the logistics and finances of the Jupyter Community Workshop series.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2020/report-on-the-jupyter-community-workshop-on/images/002-1_FMKOoximrvz6sASKu19C-g.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
</content><category term="dashboards"/><category term="events"/><category term="visualization"/><category term="workshops"/></entry><entry><title>Voilà is now a Jupyter subproject</title><link href="https://jasongrout.github.io/medium-archive/pelican/posts/2019/voila-is-now-an-official-jupyter-subproject/" rel="alternate"/><published>2019-12-29T12:11:00+00:00</published><updated>2019-12-29T12:15:00+00:00</updated><author><name>Sylvain Corlay</name></author><id>tag:jasongrout.github.io,2019-12-29:/medium-archive/pelican/posts/2019/voila-is-now-an-official-jupyter-subproject/</id><summary type="html">&lt;p&gt;It is a great pleasure to announce that the Voilà project has been incorporated as a Jupyter subproject. Voilà will now be subject to the…&lt;/p&gt;
</summary><content type="html">&lt;blockquote&gt;
&lt;p&gt;It is a great pleasure to announce that the Voilà project has been incorporated as a Jupyter subproject. Voilà will now be subject to the &lt;a href="https://github.com/jupyter/governance/blob/master/governance.md"&gt;Jupyter governance&lt;/a&gt; and &lt;a href="https://github.com/jupyter/governance/blob/master/conduct/code_of_conduct.md"&gt;code of conduct&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For reference, the Jupyter Enhancement Proposal (JEP) for the Voilà incorporation is available &lt;a href="https://github.com/jupyter/enhancement-proposals/pull/42"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="what-is-voila"&gt;What is Voilà?&lt;/h3&gt;
&lt;p&gt;Voilà helps you communicate insights, by transforming a Jupyter Notebook into a stand-alone web application you can share. It gives you control over what your readers experience in a secure and customizable interactive dashboard.&lt;/p&gt;
&lt;p&gt;The easiest way to get started with Voilà is to install it via &lt;code&gt;pip&lt;/code&gt; or &lt;code&gt;conda&lt;/code&gt; and type &lt;code&gt;voila some_notebook.ipynb&lt;/code&gt; to turn the said notebook into a dashboard.&lt;/p&gt;
&lt;p&gt;Besides, Voilà includes a templating system that allows to overload the behavior of the front-end. Using this templating system, Voilà can be used to create&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;slideshows (with voila-reveal)&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
&lt;img alt="A Voilà slideshow created with the voila-reveal template." src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/voila-is-now-an-official-jupyter-subproject/images/001-1_mp59BtUkz046smQek2-BFA.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;A Voilà slideshow created with the voila-reveal template.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;dashboards (with voila-gridstack)&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
&lt;img alt="A Voilà Dashboard based on the voila-gridstack template." src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/voila-is-now-an-official-jupyter-subproject/images/002-1_P447LmtfAnhIcCol6q6FBw.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;A Voilà Dashboard based on the voila-gridstack template.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id="why-moving-voila-under-the-jupyter-governance"&gt;Why moving Voilà under the Jupyter governance?&lt;/h3&gt;
&lt;p&gt;While the project was initially started by QuantStack, the team now comprises developers from Bloomberg, UC Berkeley, JP Morgan, and Cal Poly San Luis Obispo. OVH has been supportive of the project by kindly providing the free hosting of the gallery on their infrastructure.&lt;/p&gt;
&lt;p&gt;We believe that the &lt;em&gt;&lt;strong&gt;multi-stakeholder&lt;/strong&gt;&lt;/em&gt; nature of the Voilà project is well-suited for the Jupyter organization.&lt;/p&gt;
&lt;p&gt;The Voilà project is largely built upon Jupyter subprojects and standards.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The standard &lt;strong&gt;notebook file format&lt;/strong&gt; is the main entry point to Voilà.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;nbconvert&lt;/strong&gt; is used for the conversion to progressively-rendered HTML.&lt;/li&gt;
&lt;li&gt;naturally, we use &lt;strong&gt;jupyter_client&lt;/strong&gt; for handling the execution of notebook cells&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;jupyter_server&lt;/strong&gt; is the default back-end.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JupyterHub&lt;/strong&gt; is at the foundation of the voila-gallery project.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JupyterLab&lt;/strong&gt; components (mime renderers, input and output areas) are used in the front-end implementation. Voilà also includes a preview JupyterLab extension.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ipywidgets&lt;/strong&gt; and custom jupyter widget libraries such as bqplot, ipyvolume, ipyleaflets provide the bulk of the interactivity of Voilà applications.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Voilà is more a &lt;em&gt;remix&lt;/em&gt; of existing Jupyter components (with changes to enable that use case) than a completely new application.&lt;/p&gt;
&lt;h3 id="resources"&gt;Resources&lt;/h3&gt;
&lt;p&gt;Should you be interested in Voilà, feel free to try it on Binder or locally! You can also engage with the developer community during our public team meetings and the various GitHub repositories of the project:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the Voilà &lt;strong&gt;GitHub repository&lt;/strong&gt; is available here: &lt;a href="https://github.com/voila-dashboards/voila"&gt;https://github.com/voila-dashboards/voila&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;the &lt;strong&gt;Documentation&lt;/strong&gt; is hosted on &lt;em&gt;Read the Docs&lt;/em&gt;: &lt;a href="https://voila.readthedocs.io"&gt;https://voila.readthedocs.io&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;the &lt;strong&gt;Team Compass&lt;/strong&gt; holds the calendar for the public developer meetings, as well as the meeting minutes: &lt;a href="https://voila-dashboards.github.io"&gt;https://voila-dashboards.github.io&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;the &lt;strong&gt;Announcement&lt;/strong&gt; of the first Voilà release was published on this blog: &lt;a href="/posts/2019/and-voila/"&gt;https://blog.jupyter.org/and-voilà-f6a2c08a4a93&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="acknowledgements"&gt;&lt;strong&gt;Acknowledgements&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Voilà was started by the team of open-source developers at &lt;a href="https://twitter.com/QuantStack"&gt;QuantStack&lt;/a&gt; as a separate project, but with the full intent to incorporate it into Jupyter. The initial project development at QuantStack was funded by &lt;a href="https://twitter.com/techatbloomberg"&gt;Bloomberg&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Now, Voilà contributors work in many institutions, including UC Berkeley, Cal Poly San Luis Obispo, JP Morgan, and Faculty (formerly ASI Data Science).&lt;/li&gt;
&lt;li&gt;The Voilà Gallery is kindly hosted by &lt;a href="https://www.ovh.com/"&gt;OVH&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/voila-is-now-an-official-jupyter-subproject/images/003-1_ZrMs1GjNdEYhsbqese6xVA.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
</content><category term="dashboards"/><category term="visualization"/><category term="Voilà"/></entry><entry><title>Configure your dashboards with Voilà gridstack template</title><link href="https://jasongrout.github.io/medium-archive/pelican/posts/2019/voila-gridstack-template/" rel="alternate"/><published>2019-11-11T14:03:00+00:00</published><updated>2019-11-11T14:03:00+00:00</updated><author><name>Bartosz Telenczuk</name></author><id>tag:jasongrout.github.io,2019-11-11:/medium-archive/pelican/posts/2019/voila-gridstack-template/</id><summary type="html">&lt;p&gt;The new Voilà gridstack template simplifies creating dynamic and flexible dashboard layouts.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Voilà is a new dashboarding solution from Jupyter ecosystem. It provides an easy-to-use tool to convert your Jupyter notebooks into standalone web applications. If you have not used it before, you can learn more about Voilà from this &lt;a href="/posts/2019/and-voila/"&gt;blog post.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="and-voila-the-dashboard-templates"&gt;And voilà… the dashboard templates&lt;/h3&gt;
&lt;p&gt;To create interactive and engaging dashboards, you can add &lt;a href="https://github.com/bloomberg/bqplot"&gt;graphs&lt;/a&gt;, &lt;a href="https://github.com/jupyter-widgets/ipywidgets"&gt;interactive widgets&lt;/a&gt;, &lt;a href="https://github.com/jupyter-widgets/ipyleaflet"&gt;maps&lt;/a&gt; etc. to your notebook. Voilà will turn them into interactive applications by stripping any code and displaying the outputs in the order they appear in the notebook. If you need more flexibility over the position of the cell outputs, you can use one of the &lt;a href="/posts/2019/introducing-templates-for-jupyter-widget-layouts/"&gt;widget layout templates&lt;/a&gt; defined in the ipywidgets library. If this is not enough, with Voilà you can even turn your notebooks into &lt;a href="/posts/2019/a-slideshow-template-for-voila-apps/"&gt;interactive presentations.&lt;/a&gt; Would you also like to re-configure your dashboards the drag-and-drop way? Et voilà, the gridstack template.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/voila-gridstack-template/images/001-1_Pl6z5oPeFixFjxMEYzEpIA.mp4" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;h3 id="creating-ad-hoc-dashboards-with-gridstack"&gt;Creating ad-hoc dashboards with gridstack&lt;/h3&gt;
&lt;p&gt;If you have never used layout templates and just want to use Voilà with your existing notebooks, you can consider the new &lt;a href="https://github.com/voila-dashboards/voila-gridstack"&gt;gridstack template&lt;/a&gt; for Voilà dashboards. Simply run the following command with the path to your notebook:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;voila --template=gridstack my_notebook.ipynb --VoilaConfiguration.resources=&amp;#39;{“gridstack”: {“show_handles”: True}}&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will open a dashboard created from your notebook in a brower. By default the output cells of the notebook are laid out vertically. But you can move and resize them freely by dragging one of the handles in the corners of the cells.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="An example notebook rendered with Voilà gridstack template. The layout was configured by dragging and resizing the cells of the notebook. The notebook was downloaded from LIGO project:" src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/voila-gridstack-template/images/002-1_J_f7YGDoufB7bBw_Ik7HuA.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;An example notebook rendered with Voilà gridstack template. The layout was configured by dragging and resizing the cells of the notebook. The notebook was downloaded from LIGO project: &lt;a href="https://github.com/losc-tutorial/Data_Guide"&gt;https://github.com/losc-tutorial/Data_Guide&lt;/a&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id="positioning-widgets-with-metadata"&gt;Positioning widgets with metadata&lt;/h3&gt;
&lt;p&gt;When you are done with configuring your dashboard, Voilà enables you to persist it and a create static layout of the widgets. To achieve that you will need to edit manually the notebook metadata, but we are also planning to release a tool that will simplify the process.&lt;/p&gt;
&lt;p&gt;For example, you can add the following attributes to one of the cells (to edit the cell metadata, you need to activate the “Edit metadata” button from the View -&amp;gt; Cell toolbar menu of your notebook):&lt;/p&gt;
&lt;figure&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;extensions&amp;quot;&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="nt"&gt;&amp;quot;jupyter_dashboards&amp;quot;&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="nt"&gt;&amp;quot;version&amp;quot;&lt;/span&gt;&lt;span class="p"&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="nt"&gt;&amp;quot;views&amp;quot;&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="nt"&gt;&amp;quot;grid_default&amp;quot;&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="nt"&gt;&amp;quot;col&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&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="w"&gt;          &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;height&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;hidden&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;row&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;width&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&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="nt"&gt;&amp;quot;report_default&amp;quot;&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;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;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;trusted&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;figcaption&gt;
&lt;p&gt;Example metadata&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In Jupyter lab ≥ 1.0 you can edit the metadata using “Advanced Tools” section of “Notebook tools” sidebar (wrench icon).&lt;/p&gt;
&lt;p&gt;Then you can start Voilà with the following command:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;voila --template=gridstack my_notebook.ipynb&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This should open your dashboard with cells in the specified positions and of specified sizes.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Final layout of the dashboard configured with cell metadata. The cells are not movable in this dashboard." src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/voila-gridstack-template/images/003-1_-mUCyFUfu2JxnuzTMK0aNg.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Final layout of the dashboard configured with cell metadata. The cells are not movable in this dashboard.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id="supporting-legacy-notebooks"&gt;Supporting legacy notebooks&lt;/h3&gt;
&lt;p&gt;The metadata follow the &lt;a href="https://jupyter-dashboards-layout.readthedocs.io/en/latest/metadata.html"&gt;specification&lt;/a&gt; of the legacy &lt;em&gt;jupyter-dashboards&lt;/em&gt; project, which was an earlier solution for creating interactive dashboards. Unfortunately, the project is not maintained any more and it won’t work with the recent installations of Jupyter. However, you can open your notebooks created with &lt;em&gt;jupyter-dashboards&lt;/em&gt; &lt;strong&gt;without changes&lt;/strong&gt; with Voilà gridstack template to achieve identical rendering and give a second life to your Jupyter dashboards.&lt;/p&gt;
&lt;p&gt;(To compare the outputs, you can open the notebook with &lt;a href="https://mybinder.org/v2/gh/btel/jupyter-dashboards-binder/master"&gt;binder&lt;/a&gt; that provisions the &lt;em&gt;jupyter-dashboards&lt;/em&gt; ecosystem installed in an old version of Anaconda (2017). You can also use its design tool to lay out your widgets visually and save the cell metadata usable with Voilà gridstack template).&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Design tool implemented in legacy jupyter-dashboards project." src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/voila-gridstack-template/images/004-1_NNMhrJSc49KE-AF5HoFGTw.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Design tool implemented in legacy jupyter-dashboards project.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id="how-to-install"&gt;How to install&lt;/h3&gt;
&lt;p&gt;If you want to try out the template yourself, please install it now with:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pip install voila-gridstack&lt;/code&gt; (for pip users) or&lt;/p&gt;
&lt;p&gt;&lt;code&gt;conda install voila-gridstack&lt;/code&gt; (for conda/anaconda users).&lt;/p&gt;
&lt;p&gt;You can also try out the interactive examples with our &lt;a href="https://mybinder.org/v2/gh/voila-dashboards/voila-gridstack/master?urlpath=/voila/tree/examples"&gt;gridstack binder&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And if you have any questions or want to share your experience please reach out on our &lt;a href="https://gitter.im/QuantStack/Lobby"&gt;Gitter chat.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="credits"&gt;Credits&lt;/h3&gt;
&lt;p&gt;The development Voilà and gridstack template was initiated by the amazing team at &lt;a href="https://github.com/QuantStack"&gt;QuantStack&lt;/a&gt; that also provided financial and brain-power support.&lt;/p&gt;
&lt;h3 id="about-the-author"&gt;About the author&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://datascience.telenczuk.pl"&gt;Bartosz Telenczuk&lt;/a&gt; is a seasoned Python developer and a data scientist. He is an ardent user of Jupyter ecosystem and frequent contributor to open source software; among his projects is the &lt;a href="https://svgutils.readthedocs.io/en/latest/"&gt;svgutils&lt;/a&gt; library for composing SVG files in Python.&lt;/p&gt;
</content><category term="dashboards"/><category term="Voilà"/></entry><entry><title>A slideshow template for Voilà apps</title><link href="https://jasongrout.github.io/medium-archive/pelican/posts/2019/a-slideshow-template-for-voila-apps/" rel="alternate"/><published>2019-10-29T10:32:00+00:00</published><updated>2019-10-29T14:11:00+00:00</updated><author><name>Marianne Corvellec</name></author><id>tag:jasongrout.github.io,2019-10-29:/medium-archive/pelican/posts/2019/a-slideshow-template-for-voila-apps/</id><summary type="html">&lt;p&gt;Voilà can now serve your interactive dashboards in a slideshow format.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Last June, QuantStack &lt;a href="/posts/2019/and-voila/"&gt;announced&lt;/a&gt; the first release of &lt;a href="https://github.com/voila-dashboards/voila"&gt;Voilà&lt;/a&gt;, a solution to turn Jupyter notebooks into &lt;em&gt;standalone web applications&lt;/em&gt;. Voilà enforces &lt;em&gt;security&lt;/em&gt; (preventing arbitrary code execution) while preserving &lt;em&gt;interactivity&lt;/em&gt; (supporting interactive widgets for Jupyter notebooks, including roundtrips to the kernel). A recent addition to the ever-teeming &lt;a href="https://jupyter.org"&gt;Jupyter&lt;/a&gt; ecosystem, Voilà is flexible, extensible, and language-agnostic (running any Jupyter kernel, such as Python, R, Julia, C++).&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Voilà logo." src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/a-slideshow-template-for-voila-apps/images/001-1_JLepfTuigc_h1Gfy768BWg.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;A dashboarding solution based on Jupyter.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="getting-started-with-voila"&gt;Getting started with Voilà&lt;/h2&gt;
&lt;p&gt;Voilà is available as a Python package on &lt;a href="https://github.com/conda-forge/voila-feedstock"&gt;conda-forge&lt;/a&gt; and &lt;a href="https://pypi.org/project/voila"&gt;PyPI&lt;/a&gt;. After installing Voilà in their environment, Jupyter notebook users will see a new button in the toolbar, a button reading “Voila” with a display icon. Clicking this button will take you to a Voilà web app served &lt;a href="https://voila.readthedocs.io/en/stable/using.html#as-a-jupyter-server-extension"&gt;with the notebook server&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Screenshot of Jupyter notebook interface showing Voila button in toolbar." src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/a-slideshow-template-for-voila-apps/images/002-1_rQ6byMkg3MIOpOS0dvWOig.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Voilà use case as a Jupyter server extension.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Alternatively, you can use Voilà to create a standalone &lt;a href="https://www.tornadoweb.org"&gt;Tornado&lt;/a&gt; application. From the terminal, run &lt;code&gt;$ voila index.ipynb&lt;/code&gt; to turn notebook &lt;code&gt;index.ipynb&lt;/code&gt; into a web app. Note that you don’t launch nor run the Jupyter notebook yourself. At this point, Voilà serves the app locally.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Screencast of Voilà app (default template)." src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/a-slideshow-template-for-voila-apps/images/003-1_x-8g5Ux5j4wPmwI5TYSWkw.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Jupyter notebook turned Voilà app (&lt;a href="https://github.com/mkcor/voila-reveal-example"&gt;source&lt;/a&gt;).&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Of course, the full value of sharing these apps (typically analytics web apps, data dashboards) comes from &lt;em&gt;deploying&lt;/em&gt; them. Voilà apps can come into play at different steps of a data science workflow, from the initial step of &lt;em&gt;exploring data&lt;/em&gt; all the way to the final step of &lt;em&gt;communicating results&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="styling-voila-apps-with-layout-templates"&gt;Styling Voilà apps with layout templates&lt;/h2&gt;
&lt;p&gt;Now, you may want to customize the &lt;em&gt;layout&lt;/em&gt; of your app, especially if it is somewhat complex. For example, you can make results more readable by splitting them and using different tab panes or boxes. This you can already achieve with the &lt;code&gt;voila-gridstack&lt;/code&gt; template, also available from either &lt;a href="https://github.com/conda-forge/voila-gridstack-feedstock"&gt;conda-forge&lt;/a&gt; or &lt;a href="https://pypi.org/project/voila-gridstack"&gt;PyPI&lt;/a&gt; (still in beta).&lt;/p&gt;
&lt;p&gt;Templates are written in &lt;a href="https://jinja.palletsprojects.com"&gt;Jinja&lt;/a&gt; and use the &lt;code&gt;metadata&lt;/code&gt; field of the notebook cells. Practically, a Voilà template is a folder which lives under &lt;code&gt;PREFIX/share/jupyter/voila/templates/&lt;/code&gt;. The system of &lt;em&gt;custom templates&lt;/em&gt; is actually where the &lt;em&gt;extensibility&lt;/em&gt; of Voilà shines most. Here, we introduce &lt;a href="https://github.com/voila-dashboards/voila-reveal"&gt;voila-reveal&lt;/a&gt;, a &lt;em&gt;slideshow&lt;/em&gt; template for Voilà. It builds off of &lt;a href="https://github.com/damianavila/RISE"&gt;RISE&lt;/a&gt;, which itself builds off of &lt;a href="http://lab.hakim.se/reveal-js"&gt;reveal.js&lt;/a&gt;. The credit goes to Maarten Breddels for initiating development a few months ago.&lt;/p&gt;
&lt;h2 id="rendering-voila-apps-as-slideshows"&gt;Rendering Voilà apps as slideshows&lt;/h2&gt;
&lt;p&gt;With RISE, you can instantly turn your Jupyter notebook into a slideshow. Besides, if you share it within a &lt;a href="https://mybinder.readthedocs.io/en/latest/introduction.html#what-is-a-binder"&gt;binder&lt;/a&gt;, collaborators can readily view it in their web browser, with no need for a local setup. They can enjoy the interactive controls, if any. They are expected to run code though (&lt;a href="https://mybinder.org/v2/gh/damianavila/RISE/master?filepath=examples%2FREADME.ipynb"&gt;example&lt;/a&gt;), which may not be suitable if they are non-technical. And, even if they are, you may want to prevent arbitrary code execution.&lt;/p&gt;
&lt;p&gt;With Voilà and its new &lt;code&gt;reveal&lt;/code&gt; template, you can achieve this by sharing your RISE slideshow as a standalone web application. How so? Ever since &lt;a href="https://medium.com/@mjspeck/presenting-code-using-jupyter-notebook-slides-a8a3c3b59d67"&gt;Jupyter notebook slides&lt;/a&gt;, it has been possible to author or edit a Jupyter notebook with slideshow-related information on each cell. In principle, we could also add (or edit) these cell metadata manually (or automatically) by post-processing the JSON.&lt;/p&gt;
&lt;p&gt;Our custom slideshow template &lt;code&gt;voila-reveal&lt;/code&gt; leverages these very cell metadata (namely, subfield &lt;code&gt;slideshow&lt;/code&gt; of field &lt;code&gt;metadata&lt;/code&gt;). It handles them the exact same way &lt;a href="https://github.com/jupyter/nbconvert/blob/cda5ec4bd062a9ba01a799575942d87a509a771f/nbconvert/exporters/slides.py"&gt;nbconvert&lt;/a&gt; does when generating slideshow HTML from a notebook. It also passes default values to specific resources required by &lt;code&gt;reveal&lt;/code&gt;. These &lt;code&gt;reveal&lt;/code&gt;-required resources are: &lt;code&gt;scroll&lt;/code&gt;, &lt;code&gt;theme&lt;/code&gt;, and &lt;code&gt;transition&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To use the slideshow template with Voilà, install the &lt;code&gt;voila-reveal&lt;/code&gt; package: &lt;code&gt;$ conda install voila-reveal&lt;/code&gt; or &lt;code&gt;$ pip install voila-reveal&lt;/code&gt;. This will create and populate the &lt;code&gt;PREFIX/share/jupyter/voila/templates/reveal/&lt;/code&gt; folder. At the command line, serve the &lt;code&gt;index.ipynb&lt;/code&gt; notebook as a standalone app with the following command:&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;voila&lt;span class="w"&gt; &lt;/span&gt;index.ipynb&lt;span class="w"&gt; &lt;/span&gt;--template&lt;span class="o"&gt;=&lt;/span&gt;reveal
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;… and voilà!&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Screencast of Voilà app in slideshow format showing zoom transition (configured)." src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/a-slideshow-template-for-voila-apps/images/004-1_Pg6UNndYe0TIfRIeXy3RvA.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Voilà app rendered as a slideshow with slide transitions configured to zoom in and out (&lt;a href="https://github.com/mkcor/voila-reveal-example"&gt;source&lt;/a&gt;).&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="configuring-templates-at-the-command-line"&gt;Configuring templates at the command line&lt;/h2&gt;
&lt;p&gt;You can overwrite the above-mentioned resource defaults by passing additional options. For instance, the default value of &lt;code&gt;transition&lt;/code&gt; is &lt;code&gt;&amp;quot;fade&amp;quot;&lt;/code&gt;. To get the &lt;code&gt;&amp;quot;zoom&amp;quot;&lt;/code&gt; behaviour, we could use the following command:&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;voila&lt;span class="w"&gt; &lt;/span&gt;index.ipynb&lt;span class="w"&gt; &lt;/span&gt;--template&lt;span class="o"&gt;=&lt;/span&gt;reveal&lt;span class="w"&gt; &lt;/span&gt;--VoilaConfiguration.resources&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;{&amp;#39;reveal&amp;#39;: {&amp;#39;transition&amp;#39;: &amp;#39;zoom&amp;#39;}}&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Admittedly, it is verbose and cumbersome. Another possibility is to specify (here, &lt;code&gt;reveal&lt;/code&gt;-specific) resources in a &lt;em&gt;configuration file&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="configuring-templates-with-a-json-file"&gt;Configuring templates with a JSON file&lt;/h2&gt;
&lt;p&gt;Write your configuration file, named &lt;code&gt;conf.json&lt;/code&gt;, with the following structure:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;traitlet_configuration&amp;quot;&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="s"&gt;&amp;quot;resources&amp;quot;&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="s"&gt;&amp;quot;reveal&amp;quot;&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="s"&gt;&amp;quot;scroll&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;theme&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;simple&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;transition&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;zoom&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="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;Then, it is enough to run &lt;code&gt;$ voila index.ipynb --template=reveal&lt;/code&gt; to get slide transitions zoomed in and out; Voilà picks up the config file, as long as it lives under &lt;code&gt;PREFIX/share/jupyter/voila/templates/reveal/&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In the above &lt;a href="https://github.com/mkcor/voila-reveal-example"&gt;demo&lt;/a&gt; screencast, we showcase a scatter plot and a scatter matrix of the “iris” dataset made with &lt;a href="https://plot.ly/python/plotly-express"&gt;Plotly Express&lt;/a&gt; and customizable with &lt;a href="https://ipywidgets.readthedocs.io"&gt;ipywidgets&lt;/a&gt; dropdowns. To display the Python code for these plots, run&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;voila&lt;span class="w"&gt; &lt;/span&gt;index.ipynb&lt;span class="w"&gt; &lt;/span&gt;--template&lt;span class="o"&gt;=&lt;/span&gt;reveal&lt;span class="w"&gt; &lt;/span&gt;--strip_sources&lt;span class="o"&gt;=&lt;/span&gt;False
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To turn on scrollbars, so you can view the plots entirely, run&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;voila&lt;span class="w"&gt; &lt;/span&gt;index.ipynb&lt;span class="w"&gt; &lt;/span&gt;--template&lt;span class="o"&gt;=&lt;/span&gt;reveal&lt;span class="w"&gt; &lt;/span&gt;--strip_sources&lt;span class="o"&gt;=&lt;/span&gt;False&lt;span class="w"&gt; &lt;/span&gt;--VoilaConfiguration.resources&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;{&amp;#39;reveal&amp;#39;: {&amp;#39;scroll&amp;#39;: True}}&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;or edit the &lt;code&gt;scroll&lt;/code&gt; value in the configuration file!&lt;/p&gt;
&lt;h2 id="coming-next"&gt;Coming next&lt;/h2&gt;
&lt;p&gt;At the moment, you must specify the template upon launching Voilà. We would like to be able to toggle between different templates on the fly (without restarting the app). To this end, we shall support template specification as a URL parameter. We shall make &lt;em&gt;template selection&lt;/em&gt; available from the Jupyter interface as well.&lt;/p&gt;
&lt;h2 id="acknowledgments"&gt;Acknowledgments&lt;/h2&gt;
&lt;p&gt;The development of &lt;code&gt;voila-reveal&lt;/code&gt; is entirely supported by &lt;a href="https://github.com/QuantStack"&gt;QuantStack&lt;/a&gt;. The author would like to thank Jeremy Tuloup, Johan Mabille, and Sylvain Corlay for their valuable feedback on this piece.&lt;/p&gt;
&lt;h2 id="about-the-author"&gt;About the author&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/mkcor"&gt;Marianne Corvellec&lt;/a&gt; is an independent scientific software developer. She is also an independent researcher affiliated with &lt;a href="https://igdore.org"&gt;IGDORE&lt;/a&gt;. She holds a PhD in statistical physics from Ecole Normale Supérieure de Lyon, France.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/a-slideshow-template-for-voila-apps/images/005-1_ZrMs1GjNdEYhsbqese6xVA.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
</content><category term="dashboards"/><category term="Voilà"/></entry><entry><title>Introducing templates for Jupyter widgets layouts</title><link href="https://jasongrout.github.io/medium-archive/pelican/posts/2019/introducing-templates-for-jupyter-widget-layouts/" rel="alternate"/><published>2019-07-04T09:41:00+00:00</published><updated>2019-07-04T09:41:00+00:00</updated><author><name>Bartosz Telenczuk</name></author><id>tag:jasongrout.github.io,2019-07-04:/medium-archive/pelican/posts/2019/introducing-templates-for-jupyter-widget-layouts/</id><summary type="html">&lt;p&gt;Creating complex layouts of widgets (button, sliders, maps, graphs etc.) can be cumbersome. New layout templates make this task a breeze.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Notebooks come alive with Jupyter widgets, which allow users to produce interactive GUIs inline in the Jupyter notebook or JupyterLab.&lt;/p&gt;
&lt;p&gt;You can either use them to add a few interactive controls and plots in notebooks or to create fully-fledged applications and interactive dashboards. Both can be built with components from the core &lt;a href="https://ipywidgets.readthedocs.io/en/stable/examples/Widget%20List.html"&gt;built-in widgets&lt;/a&gt; such as buttons, sliders, and dropdowns, or with the rich ecosystem of custom widget libraries that built upon the Jupyter widgets framework, such as interactive maps with &lt;a href="https://github.com/jupyter-widgets/ipyleaflet"&gt;ipyleaflet&lt;/a&gt; or 2-D plots with &lt;a href="https://github.com/bloomberg/bqplot"&gt;bqplot&lt;/a&gt;. You can also combine several types of widgets together to create even richer applications.&lt;/p&gt;
&lt;p&gt;Have you ever tried creating complex widget layouts with multiple widgets placed at specific locations? The preferred approach so far has been to use nested HBox and VBox widgets to compose your layout, which can make creating complex applications a tedious task. We now have a more flexible solution: the &lt;em&gt;layout templates&lt;/em&gt;, which just landed with the latest release of the ipywidgets package.&lt;/p&gt;
&lt;h2 id="the-power-of-css-the-simplicity-of-python"&gt;The power of CSS, the simplicity of Python&lt;/h2&gt;
&lt;p&gt;Layout templates are a set of predefined layouts that allow you to combine multiple widgets on a single screen and arrange them visually. They leverage the powerful &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout"&gt;CSS Grid Layout specification&lt;/a&gt;, which is supported on most current browsers (yes, we are looking at you IE).&lt;/p&gt;
&lt;p&gt;While the CSS Grid properties were first introduced in ipywidgets 7.3, they were tricky to use as they were transparently reflecting the CSS Grid Spec API and required the knowledge of the CSS. The new layout templates of ipywidgets wrap the CSS properties with a pythonic interface and sensible defaults, so they never expose the user to the nasty CSS spec. However, they inherit all the advantages of the Grid being fully responsive (they adapt to the screen size) and super easy to use!&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Comparing the Python code with the generated CSS layout." src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/introducing-templates-for-jupyter-widget-layouts/images/001-1_0AvTf0rheCJJeNjOKIw27w.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Comparing the Python code with the generated CSS layout.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="application-like-uis-in-jupyter"&gt;Application-like UIs in Jupyter&lt;/h2&gt;
&lt;figure&gt;
&lt;img alt="AppLayout consists of a header, two side panes, a central pane, and a footer." src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/introducing-templates-for-jupyter-widget-layouts/images/002-1_nJ6g6rhPRdp8xfIq36Z-mw.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;&lt;strong&gt;AppLayout&lt;/strong&gt; consists of a header, two side panes, a central pane, and a footer.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;If you want to create a simple application-like layout, you can use &lt;code&gt;AppLayout&lt;/code&gt;, which consists of a header, a footer, two side panes, and a central pane. You can create the layout and populate it with widgets in a single command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;AppLayout(header=header,
          left_sidebar=prev_button,
          center=image,
          right_sidebar=next_button,
          footer=footer,
          grid_gap=&amp;#39;20px&amp;#39;,
          justify_items=&amp;#39;center&amp;#39;,
          align_items=&amp;#39;center&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/introducing-templates-for-jupyter-widget-layouts/images/003-1_YQrJiSx2g6GfhkIqK24RUw.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;Importantly, if your application does not need all the panes defined by &lt;code&gt;AppLayout&lt;/code&gt;, the layout has also some sensible defaults so that it can automatically merge widget locations that were not assigned.&lt;/p&gt;
&lt;h2 id="widgets-on-a-grid"&gt;Widgets on a grid&lt;/h2&gt;
&lt;figure&gt;
&lt;img alt="GridspecLayout places widgets on a rectangular grid. A single widget can span several rows or columns (or both)." src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/introducing-templates-for-jupyter-widget-layouts/images/004-1_W1gbrgs8aDSs2ZezDQ5v7Q.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;&lt;strong&gt;GridspecLayout&lt;/strong&gt; places widgets on a rectangular grid. A single widget can span several rows or columns (or both).&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;If you require more flexibility to arrange widgets, you can also try &lt;code&gt;GridLayout&lt;/code&gt;. First, you define the dimensions of a rectangular grid. Then you can place widgets on the grid either in a single cell of the grid or spanning several rows or columns (or both). This is easily achieved using the same slice-based API that you already use to select items from a NumPy array (or Python lists). If you already know matplotlib’s &lt;code&gt;GridSpec&lt;/code&gt; feature, the syntax may look familiar:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;# create a 10x2 grid layout
grid = GridspecLayout(10, 2)
&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; fill it in with widgets
grid[:, 0] = map
grid[0, 1] = zoom_slider
grid[1, 1] = basemap_selector
grid[2:, 1] = fig
&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;# set the widget properties
grid[:, 0].layout.height = &amp;#39;auto&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/introducing-templates-for-jupyter-widget-layouts/images/005-1_Bf8ZF5xTHU68f5OdrPBLtA.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;h2 id="style-me-up"&gt;Style me up&lt;/h2&gt;
&lt;p&gt;The layouts are very configurable and can be easily tuned to the needs of your application. To change the sizes of the layout and the grid intervals, you can use style attributes, such as &lt;code&gt;height&lt;/code&gt; , &lt;code&gt;width&lt;/code&gt;, and &lt;code&gt;gap-size&lt;/code&gt; options:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;AppLayout(grid_gap=&amp;#39;20px&amp;#39;,
          height=&amp;quot;200px&amp;quot;,
          width=&amp;quot;50%&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The size units are directly inherited from the CSS standard. More examples of style attributes can be found in the &lt;a href="https://ipywidgets.readthedocs.io/en/latest/examples/Layout%20Templates.html"&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So please go ahead and install the pre-release of ipywidgets that includes this new feature (&lt;code&gt;pip install --upgrade ipywidgets&lt;/code&gt;) and take the new layout templates for a spin. We are looking forward to your feedback!&lt;/p&gt;
&lt;h2 id="acknowledgments"&gt;Acknowledgments&lt;/h2&gt;
&lt;p&gt;The author is a seasoned Python developer and a data scientist. He loves contributing to open source software; among others he is the creator and maintainer of the &lt;a href="https://svgutils.readthedocs.io/en/latest/"&gt;svgutils&lt;/a&gt; library.&lt;/p&gt;
&lt;p&gt;The development of the ipywidgets layout templates was kindly supported by &lt;a href="https://twitter.com/QuantStack"&gt;QuantStack&lt;/a&gt;.&lt;/p&gt;
</content><category term="dashboards"/><category term="widgets"/></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>Jupyter Community Workshop: Dashboarding with Project Jupyter</title><link href="https://jasongrout.github.io/medium-archive/pelican/posts/2019/jupyter-community-workshop-dashboarding-with-project/" rel="alternate"/><published>2019-02-19T18:02:00+00:00</published><updated>2019-02-19T18:23:00+00:00</updated><author><name>Sylvain Corlay</name></author><id>tag:jasongrout.github.io,2019-02-19:/medium-archive/pelican/posts/2019/jupyter-community-workshop-dashboarding-with-project/</id><summary type="html">&lt;p&gt;We have some exciting news about the Jupyter Community Workshop on dashboarding!&lt;/p&gt;
</summary><content type="html">&lt;p&gt;We have some exciting news about the &lt;a href="/posts/2019/jupyter-community-workshops/"&gt;Jupyter Community Workshop&lt;/a&gt; on dashboarding!&lt;/p&gt;
&lt;p&gt;The workshop will be held in &lt;strong&gt;Paris&lt;/strong&gt;, France, from &lt;strong&gt;June 3rd to June 6th&lt;/strong&gt;, 2019. The event is being hosted at Center for Interdisciplinary Research (&lt;a href="https://cri-paris.org/"&gt;CRI&lt;/a&gt;), in the heart of Paris.&lt;/p&gt;
&lt;p&gt;The workshop committee consists of Maarten Breddels (&lt;a href="https://www.maartenbreddels.com/"&gt;Freelance&lt;/a&gt;), Pascal Bugnion (&lt;a href="https://faculty.ai"&gt;Faculty.ai&lt;/a&gt;), Sylvain Corlay (&lt;a href="http://quantstack.net/"&gt;QuantStack&lt;/a&gt;), Alexandre Gramfort (&lt;a href="https://team.inria.fr/parietal/"&gt;INRIA&lt;/a&gt;), and Vidar Tonaas Fauske (&lt;a href="https://www.simula.no/"&gt;Simula&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;The workshop will last four days, with hands-on discussions, hacking sessions, and technical presentations. The goal of the event is to foster collaboration and the sharing of knowledge between downstream library authors and contributors, and favor upstream contributions.&lt;/p&gt;
&lt;p&gt;Should you be interested in joining us for this workshop, please fill this &lt;a href="https://docs.google.com/forms/d/1T8rwWch1MBf_k6qSaaBTws-oqsO7tr-n4Gkmv2AUZ40"&gt;&lt;strong&gt;Google Form&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In addition to the Community Workshop, we plan on holding a public Meetup on June 5th, in partnership with the &lt;a href="https://www.meetup.com/PyData-Paris/"&gt;PyData Paris Meetup&lt;/a&gt;, with a series of lightning talks of Project Jupyter and related projects.&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;Why a Workshop on Dashboarding?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The Jupyter ecosystem has great tools for teaching, exploration and development. Dashboards allow users to interact with a kernel with interactive controls, plots, maps, etc., and allow researchers and data scientists to share their results with students, with their peers, and with the general public. Currently, users of Jupyter are (mostly) forced towards other Python or R libraries or they make direct use of front-end technologies or develop directly in JavaScript.&lt;/p&gt;
&lt;p&gt;There are existing early technologies that allow serving dashboards based on notebooks, most notably &lt;a href="https://github.com/QuantStack/voila"&gt;voila&lt;/a&gt;. The goal of this workshop is to gather core Jupyter widgets developers, members of the community and users with experience in dashboarding to bring dashboarding to a level where it can be used by all members of the Jupyter ecosystem. Ultimately, we envisage users being able to develop and deploy dashboards entirely within the Jupyter ecosystem.&lt;/p&gt;
&lt;p&gt;We will lay the foundations for dashboarding as a first-class citizen in the Jupyter ecosystem.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Acknowledgements&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This would not have been possible without the generous support provided by &lt;a href="https://www.techatbloomberg.com/"&gt;Bloomberg&lt;/a&gt;, who made this workshop series possible.&lt;/p&gt;
&lt;p&gt;We are also grateful to the &lt;a href="https://cri-paris.org/"&gt;CRI&lt;/a&gt; for gracefully hosting the dashboarding community workshop.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://jasongrout.github.io/medium-archive/pelican/posts/2019/jupyter-community-workshop-dashboarding-with-project/images/001-1_r86y02IscdD91lt-mwYswg.jpeg" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
</content><category term="dashboards"/><category term="events"/><category term="workshops"/></entry></feed>