Skip to content

IPYNB to PY Converter

Get the code out of a .ipynb file as a Python script: every code cell in order, the Markdown as comments, and IPython magics turned into calls or commented out. R and Julia notebooks give .r and .jl files. Nothing is uploaded.

v2026.10.16

Open a Jupyter notebook

No Jupyter, no install, no upload.

Sample

bike-rides.ipynb

Python 3 (ipykernel)Python 3.12.4nbformat 4.512 cells · 154 words · 1 picture

#!/usr/bin/env python
# coding: utf-8

# # Bike rides and rain: a short walkthrough
# 
# A week of **made-up** numbers from a small town's bike-share scheme. It shows what a notebook can hold: Markdown, code, a table, a chart, maths, a warning and, at the end, an error.

# In[1]:


import pandas as pd
import matplotlib.pyplot as plt


# In[2]:


rides = pd.DataFrame({
    "day": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
    "trips": [412, 438, 395, 451, 288, 230],
    "rain_mm": [0.0, 1.2, 4.5, 0.0, 9.8, 14.1],
}).set_index("day")
rides


# ## How busy was the week?
# 
# The mean number of trips per day is
# 
# $$\bar{x} = \frac{1}{n}\sum_{i=1}^{n} x_i$$
# 
# where $n$ is the number of days and $x_i$ is the number of trips on day $i$.

# In[3]:


mean = rides["trips"].mean()
print(f"Mean trips per day: {mean:.1f}")
print(f"Busiest day: {rides['trips'].idxmax()}")


# In[4]:


import warnings

if rides["rain_mm"].max() > 10:
    warnings.warn("Saturday had over 10 mm of rain; the gauge reads high in storms.")


# ## Rain and riding
# 
# Fewer people rode on wet days. Pearson’s correlation coefficient measures how closely two columns move together, from −1 to 1:
# 
# $$r = \frac{\sum_i (x_i - \bar{x})(y_i - \bar{y})}{\sqrt{\sum_i (x_i - \bar{x})^2}\,\sqrt{\sum_i (y_i - \bar{y})^2}}$$

# In[5]:


fig, ax = plt.subplots(figsize=(6.4, 3.6))
ax.bar(rides.index, rides["trips"], color="#4878d0")
ax.set_ylabel("Trips")
ax.set_title("Bike-share trips per day")
plt.show()


# In[6]:


round(rides["trips"].corr(rides["rain_mm"]), 3)


# ### A day that isn’t there
# 
# There is no Sunday in the data, so asking for it raises a `KeyError`. This is what a traceback looks like:

# In[7]:


rides.loc["Sun"]


# ### What next
# 
# - [x] Load a week of rides
# - [x] Chart them
# - [ ] Add the weekend’s weather from the town’s own gauge
# 
# > Made-up data, made for this example. Any resemblance to a real town is a coincidence.

Bike rides and rain: a short walkthrough

A week of made-up numbers from a small town's bike-share scheme. It shows what a notebook can hold: Markdown, code, a table, a chart, maths, a warning and, at the end, an error.

In [1]
import pandas as pd
import matplotlib.pyplot as plt
In [2]
rides = pd.DataFrame({
    "day": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
    "trips": [412, 438, 395, 451, 288, 230],
    "rain_mm": [0.0, 1.2, 4.5, 0.0, 9.8, 14.1],
}).set_index("day")
rides
Out [2]
trips rain_mm
day
Mon 412 0.0
Tue 438 1.2
Wed 395 4.5
Thu 451 0.0
Fri 288 9.8
Sat 230 14.1

How busy was the week?

The mean number of trips per day is

xˉ=1n∑i=1nxi\bar{x} = \frac{1}{n}\sum_{i=1}^{n} x_i

where nn is the number of days and xix_i is the number of trips on day ii.

In [3]
mean = rides["trips"].mean()
print(f"Mean trips per day: {mean:.1f}")
print(f"Busiest day: {rides['trips'].idxmax()}")
Mean trips per day: 369.0
Busiest day: Thu
In [4]
import warnings

if rides["rain_mm"].max() > 10:
    warnings.warn("Saturday had over 10 mm of rain; the gauge reads high in storms.")
/tmp/ipykernel_4120/2715331896.py:4: UserWarning: Saturday had over 10 mm of rain; the gauge reads high in storms.
  warnings.warn("Saturday had over 10 mm of rain; the gauge reads high in storms.")

Rain and riding

Fewer people rode on wet days. Pearson’s correlation coefficient measures how closely two columns move together, from −1 to 1:

r=∑i(xi−xˉ)(yi−yˉ)∑i(xi−xˉ)2 ∑i(yi−yˉ)2r = \frac{\sum_i (x_i - \bar{x})(y_i - \bar{y})}{\sqrt{\sum_i (x_i - \bar{x})^2}\,\sqrt{\sum_i (y_i - \bar{y})^2}}

In [5]
fig, ax = plt.subplots(figsize=(6.4, 3.6))
ax.bar(rides.index, rides["trips"], color="#4878d0")
ax.set_ylabel("Trips")
ax.set_title("Bike-share trips per day")
plt.show()
Image output of cell 8
In [6]
round(rides["trips"].corr(rides["rain_mm"]), 3)
Out [6]
-0.979

A day that isn’t there

There is no Sunday in the data, so asking for it raises a KeyError. This is what a traceback looks like:

In [7]
rides.loc["Sun"]

KeyError: 'Sun'

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
Cell In[7], line 1
----> 1 rides.loc["Sun"]

File ~/.venv/lib/python3.12/site-packages/pandas/core/indexes/base.py:3812, in Index.get_loc(self, key)
   3810     return self._engine.get_loc(casted_key)
   3811 except KeyError as err:
-> 3812     raise KeyError(key) from err

KeyError: 'Sun'

What next

  • Load a week of rides
  • Chart them
  • Add the weekend’s weather from the town’s own gauge

Made-up data, made for this example. Any resemblance to a real town is a coincidence.

Your notebook is read on this device and never uploaded. Check it yourself

How this works: Method, 5 sources, Checked against 2 worked examples,

How this works

Method

The .ipynb file is read in the browser as the nbformat JSON it is: every cell, its last outputs and its attachments. Markdown is drawn with GitHub Flavored Markdown and maths with KaTeX, code is coloured by the notebook’s language, and each output shows its richest format, as JupyterLab chooses. All HTML from the notebook is sanitised first and nothing from other sites is loaded. PDF comes from the browser’s print engine; HTML, script and Markdown files are written in the page.

How it’s tested

2 worked examples for this page are checked by automated tests before every release: given the inputs, the tool must show the expected answer.

Privacy

On your device. Nothing you enter or open leaves this browser. About privacy labels

Changes

  • First published: open a .ipynb file with its outputs, maths and colours, and save it as PDF, HTML, a script or Markdown.

Every change on What’s new

How we make toolsReport a mistake

From notebook cells to a script you can run

A notebook is a good place to explore and a poor place to run code on a schedule, test it or review it in a pull request. Turning it into a script is the usual next step: the cells become one file, in the order they appear, that python can run from top to bottom.

The script follows the layout of jupyter nbconvert --to script. It starts with a #!/usr/bin/env python line, and each code cell comes after a comment like # In[3]:, the cell’s execution count, so you can match the script to the notebook. Markdown cells become comment lines, which keeps the author’s explanation next to the code it explains.

IPython has its own commands that plain Python doesn’t understand: line magics such as %matplotlib inline or %timeit, cell magics such as %%bash, and shell commands that start with an exclamation mark. nbconvert rewrites them as get_ipython() calls, which only work inside IPython. Choose Comment out magics instead and they become comments, so python script.py runs on its own; you may need to replace a pip install line with a requirements file.

Check the order before you run it. Notebook cells are often run out of order while exploring, and the In [n] numbers in the comments show the order they last ran in. A script always runs top to bottom.

Good to know

How to convert a Jupyter notebook to PY3 steps, all on your device
  1. Open the notebook. Drop the .ipynb file on the card or choose it. The script appears below the notebook as you will get it.
  2. Choose how to treat magics. Keep IPython’s calls, as nbconvert writes them, or comment the magics out so the script runs under plain Python.
  3. Download the script. Press Save .py, or copy the script straight into your editor.

Frequently Asked Questions

Is this the same as nbconvert --to script?

It follows the same layout: the shebang and coding lines, an # In[n]: marker before each code cell, Markdown as comments and magics as get_ipython() calls. Spacing may differ slightly, but the code is the same.

What happens to %matplotlib inline and !pip install?

By default they become get_ipython().run_line_magic(…) and get_ipython().system(…), as nbconvert writes them. Choose Comment out magics to turn them into comments so the file runs under plain Python.

Can I leave the Markdown out?

Yes. Turn off Markdown as comments to get the code cells alone.

Does it work for R or Julia notebooks?

Yes. The script takes the notebook’s language and file ending, .r for R and .jl for Julia, with # comments. Magics are only rewritten for Python.

“Jupyter” is a trademark of Project Jupyter, used here only to say which files this viewer opens. Binary Decimal is not affiliated with or endorsed by Project Jupyter.