Plot matplotlib: menghilangkan sumbu, legenda dan spasi putih

285

Saya baru mengenal Python dan Matplotlib, saya hanya ingin menerapkan colormap ke gambar dan menulis gambar yang dihasilkan, tanpa menggunakan sumbu, label, judul atau apa pun yang biasanya secara otomatis ditambahkan oleh matplotlib. Inilah yang saya lakukan:

def make_image(inputname,outputname):
    data = mpimg.imread(inputname)[:,:,0]
    fig = plt.imshow(data)
    fig.set_cmap('hot')
    fig.axes.get_xaxis().set_visible(False)
    fig.axes.get_yaxis().set_visible(False)
    plt.savefig(outputname)

Ini berhasil menghilangkan sumbu gambar, tetapi gambar yang disimpan menyajikan padding putih dan bingkai di sekitar gambar yang sebenarnya. Bagaimana saya bisa menghapusnya (setidaknya lapisan putih)? Terima kasih

sunmat
sumber
2
Semua solusi pada pertanyaan ini difokuskan imshow. Jika Anda memiliki sebar sebaran, jawaban berikut mungkin dapat membantu Anda: stackoverflow.com/a/40727744/4124317
ImportanceOfBeingErnest

Jawaban:

373

Saya berpikir bahwa perintah axis('off')menangani salah satu masalah lebih ringkas daripada mengubah setiap sumbu dan perbatasan secara terpisah. Namun masih meninggalkan ruang putih di sekitar perbatasan. Menambahkan bbox_inches='tight'ke savefigperintah hampir membuat Anda di sana, Anda dapat melihat pada contoh di bawah ini bahwa ruang putih yang tersisa jauh lebih kecil, tetapi masih ada.

Perhatikan bahwa versi yang lebih baru dari matplotlib mungkin memerlukan bbox_inches=0alih-alih string 'tight'(via @episodeyang dan @kadrach)

from numpy import random
import matplotlib.pyplot as plt

data = random.random((5,5))
img = plt.imshow(data, interpolation='nearest')
img.set_cmap('hot')
plt.axis('off')
plt.savefig("test.png", bbox_inches='tight')

masukkan deskripsi gambar di sini

Doyan
sumber
4
Mengikuti saran unutbu, Anda bisa menggunakan fig = plt.figure(), ax = plt.axes([0,0,1,1]), kemudian plt.imshow(data,interpolation="nearest". Dikombinasikan dengan plt.axis("off"), semestinya itu menyingkirkan segala sesuatu di samping gambar itu sendiri, semoga!
PhilMacKay
5
Menggabungkan metode dari pertanyaan ({fig.axes.get_xaxis (). Set_visible (False) & fig.axes.get_yaxis (). Set_visible (False)} dengan {plt.axis ('off')}) memperbaiki masalah untuk saya. (Tidak ada spasi putih lagi). Dan jangan lupa untuk mengatur {pad_inches} Anda di savefig ke 0.
Domagoj
3
Saya baru saja menemukan masalah ini, tidak ada solusi di utas ini, dan yang terhubung, yang berfungsi. Namun secara eksplisit menentukan bbox_inches=0melakukan trik.
Kadad
1
Perhatikan bahwa jika Anda 'memplot' barang di atas plt.imshow, seperti pada plt.plot (x, y), Anda perlu memastikan bahwa Anda mengatur xlim dan ylim ke ukuran matriks.
Mathusalem
1
ini tidak berfungsi lagi. Butuh waktu satu jam untuk mencari tahu. Lihat jawaban di bawah ini.
episodeyang
107

Saya belajar trik ini dari matehat, di sini :

import matplotlib.pyplot as plt
import numpy as np

def make_image(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)
    plt.set_cmap('hot')
    ax.imshow(data, aspect='equal')
    plt.savefig(outputname, dpi=dpi)

# data = mpimg.imread(inputname)[:,:,0]
data = np.arange(1,10).reshape((3, 3))

make_image(data, '/tmp/out.png')

hasil panen

masukkan deskripsi gambar di sini

unutbu
sumber
3
Saya cukup yakin Anda memiliki jawaban yang benar (walaupun mungkin ada lebih dari satu cara untuk melakukannya), tetapi saya bertanya-tanya apakah Anda dapat menjelaskan mengapa itu jawaban yang benar? Bagaimana dengan kode Anda yang menghilangkan ruang kosong?
Yann
4
@Yann, di samping dokumentasi, saya merasa sangat membantu untuk berkomentar satu baris pada satu waktu untuk melihat efek apa yang dimiliki setiap perintah. Ini cara empiris!
unutbu
4
Garis yang menghilangkan batas putih adalah plt.Axes(fig, [0,0,1,1]). Ini memberitahu matplotlib untuk membuat satu set sumbu dengan sudut kiri bawah pada titik yang terletak di (0%, 0%), dan dengan lebar dan tinggi (100%, 100%).
PhilMacKay
Ini adalah jawaban yang lebih benar, karena tidak hanya menghilangkan ruang putih untuk gambar yang disimpan tetapi juga untuk plot layar.
MaxNoe
Terima kasih, ini adalah solusi HANYA berfungsi dengan baik di Ubuntu saya :)
AlphaGoMK
56

Kemungkinan solusi paling sederhana:

Saya hanya menggabungkan metode yang dijelaskan dalam pertanyaan dan metode dari jawaban oleh Hooked.

fig = plt.imshow(my_data)
plt.axis('off')
fig.axes.get_xaxis().set_visible(False)
fig.axes.get_yaxis().set_visible(False)
plt.savefig('pict.png', bbox_inches='tight', pad_inches = 0)

Setelah kode ini tidak ada spasi putih dan tidak ada bingkai.

Tidak ada spasi putih, kapak atau bingkai

Domagoj
sumber
3
Metode Anda memang menghapus semua spasi putih di sekitar gambar ini, kerja bagus, tapi saya masih tidak tahu mengapa menambahkan perintah fig.axes.get_xaxis().set_visible(False)menyelesaikan masalah. Terima kasih
ollydbg23
5
Ya jika Anda tidak memanggil perintah ini sebagian besar ruang putih akan dihapus. Namun dalam kasus saya masih ada beberapa ruang antara plot saya dan tepi gambar .png (mungkin 2px lebar). Dengan memanggil perintah berikut, saya telah menyingkirkan ruang keras kepala itu.
Domagoj
3
Perhatikan, bagaimanapun, bahwa di atas akan gagal di hadapan beberapa sumbu dalam gambar yang sama (dalam kasus saya gambar tertanam dalam plot). Solusi:, fig.axes[0]dan secara umum semua atau sumbu yang dipilih.
Ioannis Filippidis
29

Tidak ada yang disebutkan imsave, yang membuat ini satu kalimat:

import matplotlib.pyplot as plt
import numpy as np

data = np.arange(10000).reshape((100, 100))
plt.imsave("/tmp/foo.png", data, format="png", cmap="hot")

Langsung menyimpan gambar apa adanya, yaitu tidak menambahkan sumbu atau perbatasan / padding.

masukkan deskripsi gambar di sini

luator
sumber
Inilah yang paling sering saya lakukan, tetapi ada beberapa contoh ketika saya membutuhkan colorbar, dan dalam kasus ini imsave tidak bisa menyelamatkan saya.
Elias
9

Anda juga bisa menentukan tingkat gambar hingga bbox_inchesargumen. Ini akan menghilangkan lapisan putih di sekitar sosok itu.

def make_image(inputname,outputname):
    data = mpimg.imread(inputname)[:,:,0]
    fig = plt.imshow(data)
    fig.set_cmap('hot')
    ax = fig.gca()
    ax.set_axis_off()
    ax.autoscale(False)
    extent = ax.get_window_extent().transformed(plt.gcf().dpi_scale_trans.inverted())
    plt.savefig(outputname, bbox_inches=extent)
gypaetus
sumber
8

Ini harus menghapus semua bantalan dan batas:

from matplotlib import pyplot as plt

fig = plt.figure()
fig.patch.set_visible(False)

ax = fig.add_subplot(111)

plt.axis('off')
plt.imshow(data)

extent = ax.get_window_extent().transformed(fig.dpi_scale_trans.inverted())
plt.savefig("../images/test.png", bbox_inches=extent)
Vlady Veselinov
sumber
Jawaban yang diremehkan! Ini membuat saya seperti 99% dari perjalanan ke sana. Harus lebih dipilih karena itu yang paling up-to-date
Nathan
Ini juga berfungsi jika Anda tidak memiliki objek Axes ( ax) dengan extent = plt.gca().get_window_extent().transformed(fig.dpi_scale_trans.inverted()).
Roti panggang
3

Jawaban terunggah tidak berfungsi lagi. Untuk membuatnya bekerja, Anda perlu secara manual menambahkan sumbu yang diatur ke [0, 0, 1, 1], atau menghapus patch di bawah gambar.

import matplotlib.pyplot as plt

fig = plt.figure(figsize=(5, 5), dpi=20)
ax = plt.Axes(fig, [0., 0., 1., 1.])
fig.add_axes(ax)
plt.imshow([[0, 1], [0.5, 0]], interpolation="nearest")
plt.axis('off')                                # same as: ax.set_axis_off()

plt.savefig("test.png")

Atau, Anda bisa menghapus tambalan. Anda tidak perlu menambahkan subplot untuk menghapus paddings. Ini disederhanakan dari jawaban Vlady di bawah ini

fig = plt.figure(figsize=(5, 5))
fig.patch.set_visible(False)                   # turn off the patch

plt.imshow([[0, 1], [0.5, 0]], interpolation="nearest")
plt.axis('off')

plt.savefig("test.png", cmap='hot')

Ini diuji dengan versi 3.0.3pada 2019/06/19. Gambar lihat di bawah:

masukkan deskripsi gambar di sini

Hal yang lebih sederhana untuk dilakukan adalah menggunakan pyplot.imsave. Untuk detailnya, lihat jawaban luator di bawah

episodeyang
sumber
bagi saya hanya versi Axes yang berfungsi. saya mendapatkan padding dengan versi patch dimatikan. terima kasih!
save_jeff
2

Saya menyukai jawaban ubuntu , tetapi itu tidak menunjukkan secara eksplisit bagaimana mengatur ukuran untuk gambar non-kotak out-of-the-box, jadi saya memodifikasinya untuk mudah salin-tempel:

import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np

def save_image_fix_dpi(data, dpi=100):
    shape=np.shape(data)[0:2][::-1]
    size = [float(i)/dpi for i in shape]

    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)
    fig.savefig('out.png', dpi=dpi)
    plt.show()

Menyimpan gambar tanpa batas itu mudah, apa pun dpi yang Anda pilih jika pixel_size / dpi = ukuran disimpan.

data = mpimg.imread('test.png')
save_image_fix_dpi(data, dpi=100)

masukkan deskripsi gambar di sini

Namun tampilan itu seram. Jika Anda memilih dpi kecil, ukuran gambar Anda bisa lebih besar dari layar Anda dan Anda mendapatkan batas selama tampilan. Namun demikian, ini tidak mempengaruhi tabungan.

Sehingga untuk

save_image_fix_dpi(data, dpi=20)

Layar menjadi berbatasan (tetapi menyimpan karya): masukkan deskripsi gambar di sini

csnemes
sumber
1

Pertama, untuk format gambar tertentu (yaitu TIFF ) Anda sebenarnya dapat menyimpan colormap di header dan sebagian besar pemirsa akan menampilkan data Anda dengan colormap.

Untuk menyimpan matplotlibgambar yang sebenarnya , yang dapat berguna untuk menambahkan anotasi atau data lain ke gambar, saya telah menggunakan solusi berikut:

fig, ax = plt.subplots(figsize=inches)
ax.matshow(data)  # or you can use also imshow
# add annotations or anything else
# The code below essentially moves your plot so that the upper
# left hand corner coincides with the upper left hand corner
# of the artist
fig.subplots_adjust(left=0, right=1, top=1, bottom=0, wspace=0, hspace=0)
# now generate a Bbox instance that is the same size as your
# single axis size (this bbox will only encompass your figure)
bbox = matplotlib.transforms.Bbox(((0, 0), inches))
# now you can save only the part of the figure with data
fig.savefig(savename, bbox_inches=bbox, **kwargs)
David Hoffman
sumber
0

Terima kasih atas jawaban luar biasa dari semua orang ... Saya memiliki masalah yang sama persis dengan keinginan untuk merencanakan hanya gambar tanpa bantalan tambahan / ruang dll, jadi sangat senang menemukan ide semua orang di sini.

Terlepas dari gambar tanpa padding, saya juga ingin dapat dengan mudah menambahkan anotasi dll, lebih dari sekadar plot gambar sederhana.

Jadi apa yang akhirnya saya lakukan adalah menggabungkan jawaban David dengan csnemes ' untuk membuat pembungkus sederhana pada saat pembuatan gambar. Saat Anda menggunakannya, Anda tidak perlu melakukan perubahan nanti dengan imsave () atau yang lainnya:

def get_img_figure(image, dpi):
    """
    Create a matplotlib (figure,axes) for an image (numpy array) setup so that
        a) axes will span the entire figure (when saved no whitespace)
        b) when saved the figure will have the same x/y resolution as the array, 
           with the dpi value you pass in.

    Arguments:
        image -- numpy 2d array
        dpi -- dpi value that the figure should use

    Returns: (figure, ax) tuple from plt.subplots
    """

    # get required figure size in inches (reversed row/column order)
    inches = image.shape[1]/dpi, image.shape[0]/dpi

    # make figure with that size and a single axes
    fig, ax = plt.subplots(figsize=inches, dpi=dpi)

    # move axes to span entire figure area
    fig.subplots_adjust(left=0, right=1, top=1, bottom=0, wspace=0, hspace=0)

    return fig, ax
Richard
sumber