Edit Python in Neovim, Run in Jupyter: A Clean Jupytext Paired Workflow
In quantitative research and data science, we often use Jupyter notebooks for the interactive execution and visualization of code. However, jupyter notebooks have some limitations:
- they can be clunky to edit, especially for large codebases.
- Version control with notebooks is difficult due to their JSON format.
- IDEs often trade off efficiency for convenience.
But with Jupytext paired notebooks, we can bridge this gap — letting you edit .py files in Neovim and run the corresponding .ipynb notebook interactively, while keeping all previous outputs and execution counts.
1. Concept: Two Representations of the Same Notebook
Jupytext allows a Jupyter notebook to exist in two synchronized formats:
notebook.ipynb ↔ notebook.py
They share the same content and structure, synced through metadata.
Whenever you edit one and run:
jupytext --sync notebook.ipynb
the other side updates automatically.
- ✅
.ipynbkeeps all outputs and execution states - ✅
.pyis pure text — perfect for Git version control - ✅ Both stay perfectly in sync
2. Creating the Pair
Let’s say you have an existing Jupyter notebook:
jupytext --set-formats ipynb,py:percent demo.ipynb
This will:
- create a paired demo.py
- embed pairing metadata in demo.ipynb
- tell Jupytext that these two files represent the same notebook
3. What Does py:percent Mean?
The py:percent format uses familiar cell markers to split code and markdown cells, like this:
# %% [markdown]
# # Notebook title
# Some explanation text
# %%
import numpy as np
# %%
x = np.arange(10)
x
• # %% marks a new code cell
• # %% [markdown] marks a markdown cell
This syntax is recognized by VS Code, Spyder, PyCharm, and Neovim. It’s simple, human-readable, and makes jumping between cells in Vim effortless.
4. Typical Workflow: Neovim for Code, JupyterLab for Execution
Here’s how to combine them in practice.
Step 1 — Run JupyterLab
jupyter lab
Open demo.ipynb and run the first five cells.
Step 2 — Edit in Neovim
nvim demo.py
Edit the 6th cell and save the file.
Step 3 — Sync Changes
jupytext –sync demo.ipynb
Jupytext will:
- detect .py is newer than .ipynb
- update the notebook source accordingly
- preserve outputs and execution counts for unchanged cells
- clear outputs for modified cells only
Back in JupyterLab, refresh the notebook — you’ll see updated code, with old results intact for untouched cells.
🎯 Result: you can write in Vim, run in Jupyter, and keep your notebook history.
- Optional: Global Jupytext Config
To avoid repeating the pairing command every time, create a .jupytext.toml file in your project root:
.jupytext.toml
formats = "ipynb,py:percent"
sync_markers = true
Now, all notebooks will automatically use the same py:percent paired format.
References • Jupytext Official Docs • GitHub: mwouts/jupytext • Neovim IPython integration: nvim-ipy