Jupyter notebooks#
jupyblog
can turn your Jupyter notebooks into markdown (.md
) files with embedded outputs. It supports plots and HTML outputs.
Installation#
%pip install jupyblog --quiet
Note: you may need to restart the kernel to use updated packages.
Example#
Let’s run an example, we’ll download a configuration file (jupyblog.yaml
) and a sample post:
from pathlib import Path
import urllib.request
# create folder to store posts
path = Path("posts")
path.mkdir(exist_ok=True)
# folder to store a specific post
path_to_post = path / "my-jupyter-post"
path_to_post.mkdir(exist_ok=True)
# config file
urllib.request.urlretrieve(
"https://raw.githubusercontent.com/ploomber/jupyblog/master/examples/quick-start-jupyter/jupyblog.yaml",
path / "jupyblog.yaml",
)
# download post
_ = urllib.request.urlretrieve(
"https://raw.githubusercontent.com/ploomber/jupyblog/master/examples/quick-start-jupyter/my-post/post.ipynb",
path_to_post / "post.ipynb",
)
We stored everything in a posts/
directory, this is the structure that jupyblog
expectds: a directory with a jupyblog.yaml
configuration file and one directory per post:
%ls posts/
jupyblog.yaml my-jupyter-post/
The configuration file sets a few settings:
path_to_posts
: Where to store the rendered posts (path is relative to theposts/
directorypath_to_static
: Where to store any images referenced in the post (path is relative to theposts/
directoryprefix_img
: A prefix that will be applied to all image paths (e.g.,![img](path.png)
becomes![img](/images/blog/path.png)
)
These settings will depend on our blog structure configuration, these values are examples.
print(Path("posts/jupyblog.yaml").read_text())
path_to_posts: content/posts
path_to_static: static/images
prefix_img: /images/blog
Posts are organized in folders. Inside each folder we have a post file (post.ipynb
in this case) and any associated images. This means that you can reference your images with relative paths (e.g., ![img](path/to/image.png)
) so you can preview them with any Markdown editor.
%%sh
ls posts/my-jupyter-post/
post.ipynb
The only requirement for the notebook is to have a raw cell at the top with the following format:
---
title: My post
jupyblog:
execute_code: false
description: Some post description
---
Title is the title of the post, the jupyblog
section can be copied as-is, and description is the blog post description (a one-sentence summary)
Now, we use jupyblog
to create our post:
%%sh
cd posts/my-jupyter-post
jupyblog render
Input: /home/docs/checkouts/readthedocs.org/user_builds/jupyblog/checkouts/latest/doc/user-guide/posts/my-jupyter-post
Processing post "my-jupyter-post"
Post will be saved to /home/docs/checkouts/readthedocs.org/user_builds/jupyblog/checkouts/latest/doc/user-guide/posts/content/posts
Rendering markdown...
Making img links absolute and adding canonical name as prefix...
Output: /home/docs/checkouts/readthedocs.org/user_builds/jupyblog/checkouts/latest/doc/user-guide/posts/content/posts/my-jupyter-post.md
In our configuration file (jupyblog.yaml
), we said we wanted to store our rendered posts in the content/posts/
directory, let’s look at it:
%ls posts/content/posts/
my-jupyter-post.md
We see that it contains a file our rendered post, let’s look at its content. You’ll see that it’s the same content as your notebook, except it contains new code fences with the outputs of each cell:
print(Path("posts/content/posts/my-jupyter-post.md").read_text())
---
description: Some post description
jupyblog:
execute_code: false
version_jupysql: 0.0.15dev
title: My post
---
## My section
This sentence is some description:
```python
x = 21
y = 2
result = x * y
print(f"Result is: {result}")
```
<!-- #region -->
**Console output (1/1):**
```txt
Result is: 42
```
<!-- #endregion -->
Let's show a second snippet:
```python
x = 1
y = 41
result = x + y
print(f"Result is: {result}")
```
<!-- #region -->
**Console output (1/1):**
```txt
Result is: 42
```
<!-- #endregion -->
# remove example directory
import shutil
shutil.rmtree("posts")