0

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.

glS
  • 1,209
  • 6
  • 18
  • 45

2 Answers2

1

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

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
Nathaniel
  • 3,230
  • 11
  • 18
  • does this actually work for you? When I add that option the whitespace actually increases. Note that I'm interested in the case in which `data=np.random.randn(40, 100)` – glS Mar 19 '19 at 20:26
  • I think the problem is you are setting the size of the figure, preventing it from shrinking to fit the size of the plot. If you specify a square figure size and then plot a rectangle, there will be margins. You can make the background transparent instead of white using "transparent = True" in plt.savefig(). – Nathaniel Mar 19 '19 at 20:32
  • 1
    ah! this works. I tried something similar but also changing the values in `plt.Axes` which I guess was not right. Thanks – glS Mar 19 '19 at 20:46
1

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)
ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712