Why a notebook file becomes huge
Plots, HTML tables, printed logs, and widget state are stored inside the JSON. How to find the heavy cell, and what stripping outputs changes.
Updated

A notebook that “only has a few plots” can be 20 MB, and a notebook that looks short on screen can be larger than the dataset people think it contains. The file is JSON. Every saved output is text inside that JSON. Nothing about the size is mysterious once you look at which strings are long.
This sits next to what an .ipynb file contains. That page names the output types. This one is about which of those types actually dominate the byte count, and what you lose if you delete them.

Images are stored as text
A plot is usually a display_data or execute_result output whose data object has a key image/png or image/jpeg. The value is not a separate file on disk. It is a base64 string in the notebook.
Base64 turns 3 bytes of image into 4 characters of text, so the JSON is about a third larger than the PNG it came from. A chart that would be 800 KB as a .png is a bit over 1 MB of text in the notebook. Twenty of those charts, plus pretty-printed whitespace, is a file that email and Git both refuse.
Matplotlib, seaborn, and plotly’s static image export all do this. Plotly can also store a large application/vnd.plotly.v1+json bundle beside a smaller preview. You then have the figure twice: once as data the interactive frontend understands, and once as a picture.
SVG is text already (image/svg+xml). A simple line chart in SVG is small. A scatter plot of a hundred thousand points, written as one SVG element per point, is not.
The same result is often saved more than once
Jupyter asks the object for several MIME types and stores the ones it receives. A pandas DataFrame commonly appears as:
text/plain, the truncated text you see in a terminaltext/html, a full<table>with inline styles
The HTML table is the one that grows. A frame with dozens of columns and a few hundred displayed rows can be larger than the code that produced it. The plain-text copy is still stored next to it. Tools that keep “all outputs” keep both.
A stream output (output_type: "stream") is different. That is print() text. If a cell prints a row inside a loop, the notebook stores every line. There is no image, and the file is still huge. Search for "output_type": "stream" and look at the text field before you assume the size is plots.
Widget state is a second copy of the UI
Interactive widgets do not stay interactive in the file, but ipywidgets writes a snapshot under notebook metadata.widgets. That object can include model state and binary buffers, again as base64. A single 3D view or a widget that captured an array can outweigh the cells.
The notebook compressor can drop metadata.widgets and metadata.varInspector while it rewrites the file. Those keys are session leftovers. Removing them does not remove code. It does remove the saved widget snapshot, so the widget will not reappear until the notebook is run again in a frontend that understands it.
How to find the heavy part
You do not need a profiler.
- Make a copy of the
.ipynb. - Open the copy in a text editor, or convert it with IPYNB to JSON so the structure is easier to scan.
- Search for
image/png,image/jpeg,image/svg+xml,text/html, andapplication/vnd.plotly. - The long string after that key is the payload. A string of about 1,000,000 characters is on the order of a megabyte of text, and about three quarters of a megabyte of binary if it is base64.
The cell that owns that output is the one above it in the cells array. If one cell has a gallery of plots, that one cell is the file.
Also check attachments on Markdown cells. An image pasted into Markdown is sometimes stored there, as base64, under a name the Markdown references as attachment:filename. It is easy to miss because it is not in outputs.
What “make it smaller” actually deletes
There are two different operations, and they are not the same choice.
The output cleaner removes saved outputs and can clear execution counts. Markdown and code stay. Figures, printed tables, and tracebacks go. The file becomes small because the recording is gone. The next person sees the code, not the result, until someone runs it.
The compressor’s usual settings do that cleanup and a few mechanical extras: trailing whitespace on source lines is trimmed, empty Markdown cells can be dropped if you ask, widget and variable-inspector metadata is removed, and the JSON is written without indentation. Minify helps, but it is the small part. A 15 MB notebook of plots does not become 200 KB because the whitespace changed. It becomes 200 KB because the outputs were removed.
If you still need the figures, do not strip the only copy. Keep the large file locally, and share a second file with outputs removed. Say so in the message you send with it. A small notebook with a note that “plots were stripped” is honest. A small notebook that looks like the analysis never produced a figure is how grading arguments start.
The checkpoint beside the file
Jupyter autosaves a second notebook at .ipynb_checkpoints/<name>-checkpoint.ipynb. That file is an older save, not a section of the current one. It can be the large one, if you cleaned the main file later and the checkpoint still has the plots.
People zip a project folder and then open the checkpoint by mistake. The page looks almost right and the numbers are from yesterday. If a file’s name ends in -checkpoint.ipynb, or it lives in .ipynb_checkpoints, it is not the notebook the author last saved on purpose.
Git projects usually ignore that directory. A zip of the working tree does not.
A size check that matches the sample
The public sample notebook is small on purpose. It has one short stdout stream and no image. If you open it as text, there is no image/png key and no HTML table. That is what a notebook looks like after outputs that mattered were never stored, or were stored as a few lines of text.
When a real file is large, the difference is those keys, not the number of cells you see in the outline. Count the long strings. Then decide whether the person you are sending the file needs the pictures or only the code. Cleaning a notebook before you share it is the checklist for the second case, including secrets that size reduction will not remove.

