glS
glS

Reputation: 1299

Save non-square data array to figure without whitespace, using matplotlib

I'm trying to produce an image from an array using imshow, and export it to file without having any whitespace added.

In the case in which the data has equal width and height I managed to achieve this by following this answer:

import numpy as np
import matplotlib.pyplot as plt
def borderless_imshow_save(data, outputname, size=(1, 1), dpi=80):
    fig = plt.figure()
    fig.set_size_inches(size)
    ax = plt.Axes(fig, [0, 0, 1, 1])
    ax.set_axis_off()
    fig.add_axes(ax)

    ax.imshow(data);
    plt.savefig(outputname, dpi=dpi)

data = np.random.randn(40, 40)
borderless_imshow_save(data, 'test.png', dpi=100)

This works perfectly. However, I actually need to do this for data that is rectangular, that is, something like np.random.randn(40, 100).

In this case, the code above does not work, as again whitespace is produced in the final image. I tried playing with the size parameter and the arguments of plt.Axes but without success.

What's the best way to achieve this?

Note that imsave actually works here with something like

plt.imsave('test.png', np.random.randn(40, 100))

the problem with this is that with imsave I do not have access to same amount of options I have with imshow.

Upvotes: 0

Views: 338

Answers (2)

ImportanceOfBeingErnest
ImportanceOfBeingErnest

Reputation: 339430

An easy option is to not care about the actual size of the figure and just crop the image automatically while saving.

import numpy as np
import matplotlib.pyplot as plt

data = np.random.randn(40, 100)
fig, ax = plt.subplots()
ax.imshow(data)
ax.set_axis_off()
fig.savefig("data.png", bbox_inches="tight", pad_inches=0)

Upvotes: 1

Nathaniel
Nathaniel

Reputation: 3290

The problem is you are specifying a square figure size with size=(1,1) and then plotting a rectangular image. I have modified your code to eliminate the white space around the figure by automatically setting the figure size to match the dimensions of the input data. The size parameter now specifies the width of the image, and the height is scaled from that:

import numpy as np
import matplotlib.pyplot as plt

def borderless_imshow_save(data, outputname, size = 1, dpi=80):
    width = 1*size
    height = data.shape[0] / data.shape[1] * size
    size=(width, height)
    fig = plt.figure(figsize=size, dpi=dpi)
    ax = fig.add_axes([0, 0, 1, 1])
    ax.set_axis_off()

    ax.imshow(data);
    fig.savefig(outputname, dpi=dpi)

data = np.random.randn(40, 100)
borderless_imshow_save(data, 'test.png', size=5, dpi=100)

Saved image:

Image with no borders

Upvotes: 1

Related Questions