Skip to content

Instantly share code, notes, and snippets.

@savvastj
Forked from betatim/convert.sh
Created February 27, 2016 04:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save savvastj/0f388fde10d9ad562f94 to your computer and use it in GitHub Desktop.
Save savvastj/0f388fde10d9ad562f94 to your computer and use it in GitHub Desktop.
🚀 Minimal `nbconvert` template to convert jupyter notebooks to HTML + thebe (details: https://betatim.github.io/posts/really-interactive-posts/). Open the generated HTML in a browser it will look like a normal notebook except for the code cells, which you can edit and execute!
# Convert your notebook to an interactive webpage
#
# Attached a notebook (really-interactive-posts.ipynb) and the generated
# output (really-interactive-posts.html). The thebe.tpl template file is
# at the very end of the gist.
$ jupyter nbconvert --template thebe.tpl --to html <notebook.ipynb>
# You can open the generated webpage locally file://... howerver some
# resources will not load properly. Best to open it from a webserver:
$ python3 -m http.server
# or if you'd rather have a local https server (credit to: https://gist.github.com/dergachev/7028596)
# generate certificate with the following command:
$ openssl req -new -x509 -keyout server.pem -out server.pem -days 365 -nodes
$ echo "import BaseHTTPServer, SimpleHTTPServer
import ssl
httpd = BaseHTTPServer.HTTPServer(('localhost', 4443), SimpleHTTPServer.SimpleHTTPRequestHandler)
httpd.socket = ssl.wrap_socket (httpd.socket, certfile='./server.pem', server_side=True)
httpd.serve_forever()" > simple-https-server.py
# run with:
$ python simple-https-server.py
# In your browser, visit:
# https://localhost:4443
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.10.0/codemirror.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.0/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript" src="https://cdn.rawgit.com/oreillymedia/thebe/17fe0971303cac24d7e806c8f1bc8ba3c0c40b23/static/main-built.js"></script>
<script>
$(function(){
new Thebe({url:"https://tmpnb.org/",
kernel_name: "python3"});
});
</script>
</head>
<div class="cellOOO border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<h1 id="Really-Interactive-Blog-Posts">Really Interactive Blog Posts<a class="anchor-link" href="#Really-Interactive-Blog-Posts">&#182;</a></h1><p><em>This notebook first appeared as a <a href="//betatim.github.io/posts/really-interactive-blog-posts">blog post</a> on <a href="//betatim.github.io">Tim Head</a>'s blog.</em></p>
<p><em>License: <a href="http://opensource.org/licenses/MIT">MIT</a></em></p>
<p><em>(C) 2016, Tim Head.</em>
<em>Feel free to use, distribute, and modify with the above attribution.</em></p>
</div>
</div>
</div>
<div class="cellOOO border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<p>A few days ago I started making my <a href="/posts/interactive-posts/">blog posts interactive</a>.
It was cool, but required you to surf to a different page for the interactive
experience, while the original post was still non-interactive.</p>
<p><a href="//alexpearce.me">Alex</a> pointed out that really you wanted it all in one
page. Basically he was:</p>
<p><img src="/images/meh.gif" width="480" height="270" /></p>
<p>My blog setup follows <a href="https://jakevdp.github.io/blog/2013/05/07/migrating-from-octopress-to-pelican/">Jake Vanderplas'</a> pretty closely. So I created a new <a href="https://github.com/getpelican/pelican-plugins/tree/master/liquid_tags"><code>liquid_tags</code></a> plugin
that has its own template for <code>nbconvert</code> which generates HTML that <a href="https://github.com/oreillymedia/thebe">thebe</a> understands.</p>
<p>No downloading, no installing, no browsing to a separate page! Just interactive blog
posts! (Scroll down to see it in action if you do not care how it was done.)</p>
<h2 id="Do-it-yourself">Do it yourself<a class="anchor-link" href="#Do-it-yourself">&#182;</a></h2><p>I am preparing a write up of how to modify your own <a href="http://blog.getpelican.com/">pelican</a> site have an interactive section. For the keen and eager people, the most important part is using the following template with <code>nbconvert</code>:</p>
<pre><code>{%- extends 'basic.tpl' -%}
{% block codecell %}
&lt;pre data-executable&gt;
{{ cell.source }}
&lt;/pre&gt;
{% endblock codecell %}
{% block markdowncell scoped %}
&lt;div class="cellOOO border-box-sizing text_cell rendered"&gt;
{{ self.empty_in_prompt() }}
&lt;div class="inner_cell"&gt;
&lt;div class="text_cell_render border-box-sizing rendered_html"&gt;
{{ cell.source | markdown2html | strip_files_prefix }}
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
{%- endblock markdowncell %}</code></pre>
<p>It embeds code cells in simple <code>&lt;pre&gt;</code> tags and modifies non-code cells so that they do not
match the selectors used inside the notebook machinery. That is it. Then stick a bit of CSS and JS in the <code>&lt;head&gt;</code> of your web page and you are good to go (use the source of this one for inspiration).</p>
<h3 id="Credits">Credits<a class="anchor-link" href="#Credits">&#182;</a></h3><p>Compared to my previous post this setup now only relies on <a href="https://github.com/oreillymedia/thebe">thebe</a>, <a href="https://tmpnb.org">tmpnb</a>, and the kind people at <a href="https://developer.rackspace.com/">rackspace</a> who sponsor the computing power for <code>tmpnb</code>.</p>
<p>Below, the work of the jupyter development team, licensed under the 3 clause BSD license.</p>
<p>Get in touch on twitter @<a href="//twitter.com/betatim">betatim</a>.</p>
</div>
</div>
</div>
<div class="cellOOO border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<h1 id="Exploring-the-Lorenz-System-of-Differential-Equations">Exploring the Lorenz System of Differential Equations<a class="anchor-link" href="#Exploring-the-Lorenz-System-of-Differential-Equations">&#182;</a></h1>
</div>
</div>
</div>
<div class="cellOOO border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<p>In this Notebook we explore the Lorenz system of differential equations:</p>
$$
\begin{aligned}
\dot{x} & = \sigma(y-x) \\
\dot{y} & = \rho x - y - xz \\
\dot{z} & = -\beta z + xy
\end{aligned}
$$<p>This is one of the classic systems in non-linear differential equations. It exhibits a range of different behaviors as the parameters ($\sigma$, $\beta$, $\rho$) are varied.</p>
</div>
</div>
</div>
<div class="cellOOO border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<h2 id="Imports">Imports<a class="anchor-link" href="#Imports">&#182;</a></h2>
</div>
</div>
</div>
<div class="cellOOO border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<p>First, we import the needed things from IPython, NumPy, Matplotlib and SciPy.</p>
</div>
</div>
</div>
<pre data-executable>
%matplotlib inline
</pre>
<pre data-executable>
from ipywidgets import interact, interactive
from IPython.display import clear_output, display, HTML
</pre>
<pre data-executable>
import numpy as np
from scipy import integrate
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.colors import cnames
from matplotlib import animation
</pre>
<div class="cellOOO border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<h2 id="Computing-the-trajectories-and-plotting-the-result">Computing the trajectories and plotting the result<a class="anchor-link" href="#Computing-the-trajectories-and-plotting-the-result">&#182;</a></h2>
</div>
</div>
</div>
<div class="cellOOO border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<p>We define a function that can integrate the differential equations numerically and then plot the solutions. This function has arguments that control the parameters of the differential equation ($\sigma$, $\beta$, $\rho$), the numerical integration (<code>N</code>, <code>max_time</code>) and the visualization (<code>angle</code>).</p>
</div>
</div>
</div>
<pre data-executable>
def solve_lorenz(N=10, angle=0.0, max_time=4.0, sigma=10.0, beta=8./3, rho=28.0):
fig = plt.figure()
ax = fig.add_axes([0, 0, 1, 1], projection='3d')
ax.axis('off')
# prepare the axes limits
ax.set_xlim((-25, 25))
ax.set_ylim((-35, 35))
ax.set_zlim((5, 55))
def lorenz_deriv(x_y_z, t0, sigma=sigma, beta=beta, rho=rho):
"""Compute the time-derivative of a Lorenz system."""
x, y, z = x_y_z
return [sigma * (y - x), x * (rho - z) - y, x * y - beta * z]
# Choose random starting points, uniformly distributed from -15 to 15
np.random.seed(1)
x0 = -15 + 30 * np.random.random((N, 3))
# Solve for the trajectories
t = np.linspace(0, max_time, int(250*max_time))
x_t = np.asarray([integrate.odeint(lorenz_deriv, x0i, t)
for x0i in x0])
# choose a different color for each trajectory
colors = plt.cm.jet(np.linspace(0, 1, N))
for i in range(N):
x, y, z = x_t[i,:,:].T
lines = ax.plot(x, y, z, '-', c=colors[i])
plt.setp(lines, linewidth=2)
ax.view_init(30, angle)
plt.show()
return t, x_t
</pre>
<div class="cellOOO border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<p>Let's call the function once to view the solutions. For this set of parameters, we see the trajectories swirling around two points, called attractors.</p>
</div>
</div>
</div>
<pre data-executable>
t, x_t = solve_lorenz(angle=0, N=10)
</pre>
<div class="cellOOO border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<p>Using IPython's <code>interactive</code> function, we can explore how the trajectories behave as we change the various parameters.</p>
</div>
</div>
</div>
<pre data-executable>
w = interactive(solve_lorenz, angle=(0.,360.), N=(0,50), sigma=(0.0,50.0), rho=(0.0,50.0))
display(w)
</pre>
<div class="cellOOO border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<p>The object returned by <code>interactive</code> is a <code>Widget</code> object and it has attributes that contain the current result and arguments:</p>
</div>
</div>
</div>
<pre data-executable>
t, x_t = w.result
</pre>
<pre data-executable>
w.kwargs
</pre>
<div class="cellOOO border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<p>After interacting with the system, we can take the result and perform further computations. In this case, we compute the average positions in $x$, $y$ and $z$.</p>
</div>
</div>
</div>
<pre data-executable>
xyz_avg = x_t.mean(axis=1)
</pre>
<pre data-executable>
xyz_avg.shape
</pre>
<div class="cellOOO border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<p>Creating histograms of the average positions (across different trajectories) show that on average the trajectories swirl about the attractors.</p>
</div>
</div>
</div>
<pre data-executable>
plt.hist(xyz_avg[:,0])
plt.title('Average $x(t)$')
</pre>
<pre data-executable>
plt.hist(xyz_avg[:,1])
plt.title('Average $y(t)$')
</pre>
<pre data-executable>
</pre>
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
{%- extends 'basic.tpl' -%}
{% block header %}
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.10.0/codemirror.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.0/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript" src="https://cdn.rawgit.com/oreillymedia/thebe/17fe0971303cac24d7e806c8f1bc8ba3c0c40b23/static/main-bu\
ilt.js"></script>
<script>
$(function(){
new Thebe({url:"https://tmpnb.org/",
kernel_name: "python3"});
});
</script>
</head>
{% endblock header %}
{% block codecell %}
<pre data-executable>
{{ cell.source }}
</pre>
{% endblock codecell %}
{% block markdowncell scoped %}
<div class="cellOOO border-box-sizing text_cell rendered">
{{ self.empty_in_prompt() }}
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
{{ cell.source | markdown2html | strip_files_prefix }}
</div>
</div>
</div>
{%- endblock markdowncell %}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment