Stacked patches into grid, to produce visualizations like the following:

    .. image:: https://github.com/tensorpack/tensorpack/raw/master/examples/GAN/demo/BEGAN-CelebA-samples.jpg

    Args:
        patch_list(list[ndarray] or ndarray): NHW or NHWC images in [0,255].
        nr_row(int), nr_col(int): rows and cols of the grid.
            ``nr_col * nr_row`` must be no less than ``len(patch_list)``.
        border(int): border length between images.
            Defaults to ``0.05 * min(patch_width, patch_height)``.
        pad (boolean): when `patch_list` is a list, pad all patches to the maximum height and width.
            This option allows stacking patches of different shapes together.
        bgcolor(int or 3-tuple): background color in [0, 255]. Either an int
            or a BGR tuple.
        viz(bool): whether to use :func:`interactive_imshow` to visualize the results.
        lclick_cb: A callback function ``f(patch, patch index in patch_list)``
            to get called when a patch get clicked in imshow.

    Returns:
        np.ndarray: the stacked image.

def stack_patches(
        patch_list, nr_row, nr_col, border=None,
        pad=False, bgcolor=255, viz=False, lclick_cb=None):
    """
    Stacked patches into grid, to produce visualizations like the following:

    .. image:: https://github.com/tensorpack/tensorpack/raw/master/examples/GAN/demo/BEGAN-CelebA-samples.jpg

    Args:
        patch_list(list[ndarray] or ndarray): NHW or NHWC images in [0,255].
        nr_row(int), nr_col(int): rows and cols of the grid.
            ``nr_col * nr_row`` must be no less than ``len(patch_list)``.
        border(int): border length between images.
            Defaults to ``0.05 * min(patch_width, patch_height)``.
        pad (boolean): when `patch_list` is a list, pad all patches to the maximum height and width.
            This option allows stacking patches of different shapes together.
        bgcolor(int or 3-tuple): background color in [0, 255]. Either an int
            or a BGR tuple.
        viz(bool): whether to use :func:`interactive_imshow` to visualize the results.
        lclick_cb: A callback function ``f(patch, patch index in patch_list)``
            to get called when a patch get clicked in imshow.

    Returns:
        np.ndarray: the stacked image.
    """
    if pad:
        patch_list = _pad_patch_list(patch_list, bgcolor)
    patch_list = _preprocess_patch_list(patch_list)

    if lclick_cb is not None:
        viz = True
    ph, pw = patch_list.shape[1:3]

    canvas = Canvas(ph, pw, nr_row, nr_col,
                    patch_list.shape[-1], border, bgcolor)

    if lclick_cb is not None:
        def lclick_callback(img, x, y):
            idx = canvas.get_patchid_from_coord(x, y)
            lclick_cb(patch_list[idx], idx)
    else:
        lclick_callback = None

    canvas.draw_patches(patch_list)
    if viz:
        interactive_imshow(canvas.canvas, lclick_cb=lclick_callback)
    return canvas.canvas