# Plotting a grid of PIL images in Jupyter

**Date:** 2020-05-06  
**Author:** Kees C. Bakker  
**Categories:** Python  
**Original:** https://keestalkstech.com/plotting-a-grid-of-pil-images-in-jupyter/

![Plotting a grid of PIL images in Jupyter](https://keestalkstech.com/wp-content/uploads/2020/05/PlotImagesOnGridJupyterNotebook-1-scaled.jpg)

---

When working with images in a Python notebook I like to visualize them on a grid. Just calling `display` is not enough as it renders the images underneath each other. Let's use [Matplotlib](https://pypi.org/project/matplotlib/) to generate a grid of PIL images.

## Install dependencies

Let's install Pillow and Matplotlib first:

```sh
!pip --disable-pip-version-check --quiet install pillow matplotlib
```

## Download an image into PIL

First, let's create a helper to download images and convert them to PIL images. You probably won't need this, but it shows that PIL images are used (instead of files). To make things easier, I'm adding the last part of the URL path as a filename.

```py
import io
from urllib.request import urlopen, Request
from urllib.parse import urlparse
from PIL import Image
from PIL.Image import Image as PilImage

def url_to_pil(url:str) -> PilImage:
    headers = { 'User-Agent': 'Mozilla/6.0'}
    data = urlopen(Request(url, headers=headers)).read()
    bts = io.BytesIO(data)
    im = Image.open(bts)
    im.filename = urlparse(url).path
    return im
```

We can now map a bunch of URLs to PIL images like this:

```py
urls = [
    "https://images.wehkamp.nl/i/wehkamp/16420094_eb_01",
    "https://images.wehkamp.nl/i/wehkamp/16454613_mb_01",
    "https://images.wehkamp.nl/i/wehkamp/16454613_mb_01",
    "https://images.wehkamp.nl/i/wehkamp/16179041_mb_01",
    "https://images.wehkamp.nl/i/wehkamp/16392908_mb_01",
    "https://images.wehkamp.nl/i/wehkamp/16430906_eb_01",
    "https://images.wehkamp.nl/i/wehkamp/16433387_eb_01",
    "https://images.wehkamp.nl/i/wehkamp/16439873_eb_02",
    "https://images.wehkamp.nl/i/wehkamp/16353572_eb_04",
    "https://images.wehkamp.nl/i/wehkamp/16441968_eb_04",
    "https://images.wehkamp.nl/i/wehkamp/16443748_eb_03"]

images = [url_to_pil(u) for u in urls]
```

## Display images helper

Let's create a helper function that will plot the images:

```py
import matplotlib.pyplot as plt
from PIL.Image import Image as PilImage
from typing import List
import textwrap, os

def display_images(
    images: List[PilImage], 
    columns=5, width=20, height=8, max_images=15, 
    label_wrap_length=50, label_font_size=8):

    if not images:
        print("No images to display.")
        return 

    if len(images) > max_images:
        print(f"Showing {max_images} images of {len(images)}:")
        images=images[0:max_images]

    height = max(height, int(len(images)/columns) * height)
    plt.figure(figsize=(width, height))
    for i, image in enumerate(images):

        plt.subplot(int(len(images) / columns + 1), columns, i + 1)
        plt.imshow(image)

        if hasattr(image, 'filename'):
            title=image.filename
            if title.endswith("/"): title = title[0:-1]
            title=os.path.basename(title)
            title=textwrap.wrap(title, label_wrap_length)
            title="\n".join(title)
            plt.title(title, fontsize=label_font_size);
```

The *width* and *height* are in *inches*, so you might want to specify different values based on your need. Now let's call the helper for our image array:

```py
display_images(images)
```

Which results in the following plot image:

![](https://keestalkstech.com/wp-content/uploads/2020/05/PlotGridImages-1.svg)
*Showing a grid of images with some nice labels.*

The code is on GitHub, so check it out*:* [code gallery / 11. Jupyter PIL images](https://github.com/KeesCBakker/keestalkstech-code-gallery/blob/main/11.jupyter-pil-images/plotting-a-grid-of-pil-images-in-jupyter.ipynb)*.*

## Changelog

- 2021-04-15: Added the `os` import. Fixed the matplotlib warning of the subplot.
- 2020-05-08: Fixed bug with displaying a list of images that is less than half the number of columns. Now making sure there is at least 1 row rendered if we have images.
- 2020-05-07: Added labels with the filename to the grid. This makes it easier to distinguish between images. Added option for wrapping long image names. This is especially useful if file names are long.
- 2020-05-06: Initial article.
