English · 한국어
See arrays, tensors and figures while you debug Python in VS Code.
Thumbnails appear next to your variables when the debugger pauses; press Ctrl+. for the full picture.
Marketplace · Changelog · Contributing
Inspecting image data in a debugger usually means typing plt.imshow(...) into the console or dumping files by hand. This extension does that for you: while the debugger is paused it renders the variable under the cursor to a PNG and opens it beside your code. Nothing is added to your source and nothing stays behind after the session.
- Install the extension. There is nothing to configure; the libraries used for rendering are the ones already installed in the Python environment you debug.
- Open a Python file, set a breakpoint after an image has been created, and start debugging (F5).
- When the debugger pauses, a small thumbnail appears in front of every image-like variable of the current function. Hover it to see the image larger, together with its shape and dtype.
- For the full-size picture, put the cursor on the variable and press Ctrl+. (macOS ⌘+.), then choose
[Matplotlib] Preview imgor another renderer. The image opens in an editor tab next to your code.
That is all there is to it. The sections below describe each way of looking at an image in more detail.
While the debugger is paused, every local variable that can be rendered as an image gets a thumbnail the height of one text line, placed right before its name on every line that mentions it. They update when you step and disappear when the program runs on.
- Hover a thumbnail to see a larger version with the variable's type, shape and dtype, for example
img · ndarray (480, 640, 3) uint8, and links such asOpenCV · Matplotlib. Click a link to open the full-size image. The debugger's own value popup opens in the same tooltip above it; scroll down, or press Alt to show only the preview. - Only variables of the current function (the Locals scope) are shown, and only in the file the debugger is paused in. Attributes such as
self.imgare not decorated; use the Quick Fix or the hover for those. - Variables mentioned closest to the paused line are rendered first, up to
pythonImagePreview.inlineThumbnailLimitvariables per stop. - Turn this off with
pythonImagePreview.inlineThumbnailsif it gets in the way.
- Place the cursor on a variable name, for example
img,maskorself.image. - Press Ctrl+. (macOS ⌘+.). Alternatively right-click and choose Preview Image at Cursor, or click the light bulb.
- Pick a renderer. Each entry is labelled with the library that will write the image, e.g.
[OpenCV] Preview imgtreats the array as BGR,[Matplotlib] Preview imgas RGB. - The PNG opens in the column beside the editor. Run the same steps again after stepping to refresh it, or turn on
pythonImagePreview.keepHistoryto keep every version in its own tab and compare them side by side.
Only renderers whose library can be imported in the debugged interpreter are offered. If you see [Matplotlib] but not [OpenCV], cv2 is not installed in that environment. Nothing is rendered until you pick an entry, so opening the menu is cheap.
Select a piece of code, for example batch[0], img[..., 0], self.model.weight or (x - 0.5) / 0.5, and press Ctrl+.. The selection is evaluated in the paused frame and previewed like a variable. The selection has to be a single-line expression without side effects you would not want to run.
Right-click a variable in the Run and Debug › Variables panel and choose Preview Image. If several renderers apply, a picker asks which one to use. This also works for nested entries such as items of a list or attributes of an object.
Hovering a variable name while debugging shows the debugger's own value popup. Press Alt (⌥ on macOS) while the popup is open, or hold it while hovering, and it switches to the image preview popup with the same thumbnail and links as the thumbnail hover; release the key to go back. This is useful for expressions and attributes that have no thumbnail in front of them. Other extensions' hovers (for example Pylance's type information) share this popup.
Everything above works on the frame selected in the Call Stack view, and only in the file that frame belongs to. A variable with the same name in another open file is not shown, since it would be a different object. Click another frame to inspect its variables; the thumbnails switch to that frame's file and locals. The Variables view works regardless of which file is open.
VS Code can show variable values at the end of lines while paused (debug.inlineValues). The extension can replace those values with a compact img: (480, 640, 3) uint8 for image-like variables. This is off by default; set pythonImagePreview.inlineValues to images (image-like variables only) or all (every variable, image-like ones summarised).
The Library column is the library the object comes from; Renders with lists the pip packages the extension uses to write the PNG. Only renderers that are importable in the debugged interpreter are offered.
| Library | Object types | Renders with (pip) |
|---|---|---|
| NumPy, imageio, scikit-image | ndarray, memmap, MaskedArray |
opencv-python or matplotlib |
| JAX, CuPy | ArrayImpl, ndarray |
opencv-python or matplotlib |
| Pillow | Image, *ImageFile |
pillow |
| OpenCV | ndarray (written as BGR) |
opencv-python |
| Matplotlib | Figure, SubFigure, Axes |
matplotlib |
| Seaborn | Axes, FacetGrid, PairGrid, JointGrid |
matplotlib |
| Plotly | Figure |
plotly + kaleido |
| pandas | DataFrame, Series (via .plot()) |
pandas + matplotlib |
| TensorFlow | EagerTensor, ResourceVariable |
pillow |
| PyTorch | Tensor, Parameter (any device, with or without grad) |
pillow |
| SimpleITK | Image |
SimpleITK + pillow |
| nibabel | Nifti1Image, Nifti2Image, MGHImage, … |
nibabel + pillow |
| Bokeh | figure, GridPlot, Row, Column |
bokeh + selenium or playwright |
| Altair | Chart, LayerChart, HConcatChart, … |
altair + vl-convert-python |
Arrays and tensors are normalized before saving, so the common shapes just work:
- a leading batch dimension is dropped (
N×C×H×W→ first item) C×H×Wis transposed toH×W×C- a trailing single channel is squeezed
- masked entries of a
MaskedArrayare filled with 0,NaNbecomes 0 - values are mapped to
uint8:bool→ 0/255,0..1is scaled by 255,0..255is kept, anything else (uint16,-1..1tensors, …) is min-max scaled - half-precision tensors (
float16,bfloat16) are widened before conversion - medical volumes show the middle slice, min-max scaled
| Setting | Default | Description |
|---|---|---|
pythonImagePreview.cacheDirectory |
"" |
Folder for preview files. Empty uses the OS temp directory. Supports ${workspaceFolder}, ${workspaceFolderBasename}, ${fileDirname}, ${fileBasenameNoExtension}, ${userHome}, ${tmpdir} and ${env:NAME}. |
pythonImagePreview.keepHistory |
false |
Write every preview to a new file so each opens in its own tab and earlier ones stay open for comparison. Off: a variable reuses one file. |
pythonImagePreview.clearOnSessionEnd |
true |
Delete preview files when the debug session ends. |
pythonImagePreview.openBeside |
true |
Open previews beside the editor instead of in the active column. |
pythonImagePreview.grayscaleColormap |
"gray" |
Matplotlib colormap for 2-D arrays rendered with the Matplotlib renderer (gray, viridis, magma, …). |
pythonImagePreview.hoverPreview |
true |
Show shape/dtype and a thumbnail when hovering an image-like variable with Alt held. |
pythonImagePreview.hoverThumbnailWidth |
320 |
Maximum width of the hover thumbnail in pixels; the image is scaled down to fit, keeping its aspect ratio. |
pythonImagePreview.hoverThumbnailHeight |
120 |
Maximum height of the hover thumbnail in pixels. |
pythonImagePreview.inlineThumbnails |
true |
Show a small thumbnail before each mention of an image-like local variable; hover it for the larger preview. |
pythonImagePreview.inlineThumbnailHeight |
0 |
Height of the inline thumbnail in pixels; 0 follows the editor's line height. |
pythonImagePreview.inlineThumbnailLimit |
40 |
Variables rendered as inline thumbnails per stop, nearest to the paused line first. |
pythonImagePreview.inlineValues |
"off" |
images: name: shape dtype for image-like local variables only. all: other variables show their value too, as VS Code normally does. off: leave inline values to VS Code. Needs debug.inlineValues set to auto or on. |
Changes apply immediately. Switching cacheDirectory removes the folder used before.
To keep previews next to the source file, as earlier versions did:
"pythonImagePreview.cacheDirectory": "${fileDirname}/__pycache__/preview"| Command | Description |
|---|---|
Python Image Preview: Preview Image at Cursor |
Opens the Quick Fix menu with the available renderers. |
Preview Image (Variables view context menu) |
Renders the selected variable, asking which renderer to use if several apply. |
Python Image Preview: Open Settings |
Opens the Settings editor filtered to this extension. |
Python Image Preview: Clear Preview Cache |
Deletes every preview file written so far. |
The extension talks to the running debug adapter (debugpy) over the Debug Adapter Protocol. It looks the variable up in the selected frame and checks which libraries are importable there with importlib.util.find_spec, without importing them. When you pick a renderer it evaluates a small snippet in that frame which writes a PNG with the chosen library. The snippet runs inside a try/except, never touches the Matplotlib backend, and cleans up its temporaries. If rendering fails, the reason is logged to the Python Image Preview output channel.
The extension is declared as a workspace extension, so with Remote-SSH, WSL or Dev Containers it runs on the remote side next to the Python process and the preview file is opened from there. A bare attach to a debugger on another host does not work, because the PNG is written on that host.
- No thumbnails appear. The debugger must be paused in the file you are looking at, and the variable must be a local of the current function (module-level globals are not decorated when paused inside a function). Check the Python Image Preview output channel for rendering errors.
- No quick fix appears. The session must be paused, the file must be the one the selected frame is paused in, and the variable must be visible in that frame's Locals or Globals. Select the expression if it is not a plain variable.
- A renderer is missing. The library is not importable in the debugged interpreter. The output channel lists which modules were probed.
- No inline values at all. Set
debug.inlineValuestoautooron. Like VS Code itself, the extension only looks at the Locals scope. - Plain variables lost their inline values. That happens in the
imagesmode. SetpythonImagePreview.inlineValuestoallto show them as well (modules, functions and classes stay hidden), or tooffto hand inline values back to VS Code. - The hover shows the plain value, not a thumbnail. That is the debugger's hover. Hover the thumbnail icon before the name instead, or hold Alt (⌥ on macOS) while hovering the name. With Alt, other extensions' hovers (Pylance's type line, for example) share the popup; lower
pythonImagePreview.hoverThumbnailHeightif it needs scrolling. - Rendering fails. The error message offers Show Log; the Python exception is in the output channel.
- Plotly / Bokeh / Altair. These need their own export backends (
kaleido,selenium/playwright,vl-convert-python).
Proprietary. Free for personal and commercial use; redistribution and modification are not permitted. See LICENSE.md.
Daehee Yun · [email protected]










