Lô Matplotlib: loại bỏ trục, truyền thuyết và khoảng trắng


285

Tôi mới sử dụng Python và Matplotlib, tôi chỉ muốn áp dụng colormap cho một hình ảnh và viết hình ảnh kết quả, mà không sử dụng trục, nhãn, tiêu đề hoặc bất cứ thứ gì thường được tự động thêm bởi matplotlib. Đây là những gì tôi đã làm:

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)

Nó loại bỏ thành công trục của hình, nhưng hình được lưu thể hiện phần đệm trắng và khung xung quanh ảnh thực. Làm thế nào tôi có thể loại bỏ chúng (ít nhất là phần đệm trắng)? Cảm ơn


2
Tất cả các giải pháp cho câu hỏi này được tập trung vào imshow. Nếu bạn có một biểu đồ phân tán thay vì câu trả lời sau đây có thể giúp bạn: stackoverflow.com/a/40727744/4124317
ImportanceOfByingErnest

Câu trả lời:


373

Tôi nghĩ rằng lệnh axis('off')này quan tâm đến một trong những vấn đề ngắn gọn hơn là thay đổi từng trục và đường viền riêng biệt. Nó vẫn để lại khoảng trắng xung quanh biên giới. Thêm bbox_inches='tight'vào savefiglệnh gần như đưa bạn đến đó, bạn có thể thấy trong ví dụ bên dưới rằng khoảng trắng còn lại nhỏ hơn nhiều, nhưng vẫn hiện diện.

Lưu ý rằng các phiên bản mới hơn của matplotlib có thể yêu cầu bbox_inches=0thay vì chuỗi 'tight'(thông qua @epiTyang và @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')

nhập mô tả hình ảnh ở đây


4
Theo đề nghị unutbu, bạn có thể sử dụng fig = plt.figure(), ax = plt.axes([0,0,1,1])thì plt.imshow(data,interpolation="nearest". Kết hợp với plt.axis("off"), nó sẽ loại bỏ mọi thứ bên cạnh hình ảnh, hy vọng!
PhilMacKay

5
Kết hợp các phương thức từ câu hỏi ({fig.axes.get_xaxis (). Set_visible (Sai) & fig.axes.get_yaxis (). Set_visible (Sai)} với {plt.axis ('off')}) đã khắc phục sự cố cho tôi. (Không còn khoảng trắng nữa). Và đừng quên đặt {pad_inches} của bạn trong savefig thành 0.
Domagoj

3
Tôi chỉ chạy qua vấn đề này, không có giải pháp nào trong chủ đề này và các giải pháp được liên kết, hoạt động. Tuy nhiên, rõ ràng chỉ định bbox_inches=0đã lừa.
kadrach 23/2/2015

1
Lưu ý rằng nếu bạn đang 'vẽ đồ thị' trên plt.imshow, như trong plt.plot (x, y), bạn cần đảm bảo rằng bạn đặt xlim và ylim theo kích thước của ma trận.
Math Jerusalem

1
cái này không hoạt động nữa. Mất một giờ để tìm ra nó. Xem câu trả lời dưới đây.
tập

107

Tôi đã học được mẹo này từ matehat, ở đây :

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')

sản lượng

nhập mô tả hình ảnh ở đây


3
Tôi khá chắc chắn rằng bạn có câu trả lời đúng (mặc dù có lẽ có nhiều hơn một cách để làm điều đó), nhưng tôi tự hỏi liệu bạn có thể giải thích tại sao đó là câu trả lời đúng không? Điều gì về mã của bạn loại bỏ khoảng trắng?
Yann

4
@Yann, ngoài các tài liệu, tôi thấy rất hữu ích khi bình luận từng dòng một để xem tác dụng của mỗi lệnh. Đó là cách thực nghiệm!
unutbu

4
Các dòng loại bỏ các đường viền màu trắng là plt.Axes(fig, [0,0,1,1]). Điều này cho matplotlib tạo ra một tập hợp các trục có góc dưới bên trái tại điểm nằm ở (0%, 0%), và với chiều rộng và chiều cao là (100%, 100%).
PhilMacKay

Đây là câu trả lời đúng hơn, vì nó không chỉ loại bỏ khoảng trắng cho hình ảnh đã lưu mà còn cho các ô trên màn hình.
MaxNoe

Cảm ơn, đây là giải pháp DUY NHẤT hoạt động tốt trên Ubuntu của tôi :)
AlphaGoMK

56

Giải pháp đơn giản nhất có thể:

Tôi chỉ đơn giản là kết hợp phương pháp được mô tả trong câu hỏi và phương pháp từ câu trả lời của 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)

Sau mã này không có khoảng trắng và không có khung.

Không có khoảng trắng, trục hoặc khung


3
Phương pháp của bạn đã loại bỏ tất cả các khoảng trắng xung quanh hình ảnh này, hoạt động tốt, nhưng tôi vẫn không biết tại sao thêm lệnh fig.axes.get_xaxis().set_visible(False)giải quyết vấn đề. Cảm ơn
ollydbg23

5
Có nếu bạn không gọi lệnh này, hầu hết các khoảng trắng sẽ bị xóa. Tuy nhiên, trong trường hợp của tôi, vẫn còn một số khoảng trống giữa cốt truyện và cạnh của hình ảnh .png (có thể rộng 2px). Bằng cách gọi các lệnh sau tôi đã thoát khỏi những khoảng trống cứng đầu đó.
Domagoj

3
Tuy nhiên, lưu ý rằng ở trên sẽ thất bại với sự hiện diện của nhiều trục trong cùng một hình (trong trường hợp của tôi là một hình ảnh nhúng trong cốt truyện). Giải pháp: fig.axes[0]và nói chung tất cả hoặc các trục được chọn.
Ioannis Filippidis

29

Không ai đề cập đến imsave, điều này làm cho điều này một lót:

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")

Nó trực tiếp lưu trữ hình ảnh như hiện tại, tức là không thêm bất kỳ trục hoặc đường viền / phần đệm nào.

nhập mô tả hình ảnh ở đây


Đây là những gì tôi làm hầu hết thời gian, nhưng có những trường hợp khi tôi cần thanh màu, và trong những trường hợp này, tôi không thể cứu tôi.
Elias

9

Bạn cũng có thể chỉ định phạm vi của hình cho bbox_inchesđối số. Điều này sẽ thoát khỏi phần đệm trắng xung quanh hình.

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)

8

Điều này sẽ loại bỏ tất cả các phần đệm và đường viền:

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)

Câu trả lời không thể chối cãi! Điều này đã cho tôi giống như 99% của cách đó. Nên được nâng cao hơn bởi vì đó là cập nhật nhất
Nathan

Nó cũng hoạt động nếu bạn không có đối tượng Axes ( ax) với extent = plt.gca().get_window_extent().transformed(fig.dpi_scale_trans.inverted()).
Bánh mì nướng


3

Câu trả lời nâng cao không hoạt động nữa. Để làm cho nó hoạt động, bạn cần thêm thủ công một trục được đặt thành [0, 0, 1, 1] hoặc xóa bản vá trong hình.

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")

Ngoài ra, bạn chỉ có thể loại bỏ các bản vá. Bạn không cần phải thêm một subplot để loại bỏ phần đệm. Điều này được đơn giản hóa từ câu trả lời của Vladian dưới đây

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')

Điều này đã được thử nghiệm với phiên bản 3.0.3vào ngày 2019/06/19. Hình ảnh xem dưới đây:

nhập mô tả hình ảnh ở đây

Một điều đơn giản hơn nhiều để làm là sử dụng pyplot.imsave. Để biết chi tiết, xem dưới đây câu trả lời của luator


Đối với tôi chỉ có phiên bản Axes hoạt động. tôi nhận được phần đệm với phiên bản tắt. Dù sao đi nữa!
save_jeff

2

Tôi thích câu trả lời của Ubuntu , nhưng nó không hiển thị rõ ràng cách đặt kích thước cho hình ảnh không vuông, vì vậy tôi đã sửa đổi nó để dễ sao chép:

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()

Lưu hình ảnh không có viền là dễ dàng bất cứ dpi nào bạn chọn nếu pixel_size / dpi = size được giữ.

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

nhập mô tả hình ảnh ở đây

Tuy nhiên hiển thị là ma quái. Nếu bạn chọn dpi nhỏ, kích thước hình ảnh của bạn có thể lớn hơn màn hình của bạn và bạn có đường viền trong khi hiển thị. Tuy nhiên, điều này không ảnh hưởng đến tiết kiệm.

Vì vậy đối với

save_image_fix_dpi(data, dpi=20)

Màn hình trở nên viền (nhưng lưu công việc): nhập mô tả hình ảnh ở đây


1

Đầu tiên, đối với các định dạng hình ảnh nhất định (ví dụ TIFF ), bạn thực sự có thể lưu bản đồ màu trong tiêu đề và hầu hết người xem sẽ hiển thị dữ liệu của bạn bằng bản đồ màu.

Để lưu matplotlibhình ảnh thực tế , có thể hữu ích để thêm chú thích hoặc dữ liệu khác vào hình ảnh, tôi đã sử dụng giải pháp sau:

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)

0

Cảm ơn câu trả lời tuyệt vời từ mọi người ... Tôi có cùng một vấn đề với việc chỉ muốn vẽ một hình ảnh không có phần đệm / không gian thêm, v.v., vì vậy tôi đã rất vui khi tìm thấy ý tưởng của mọi người ở đây.

Ngoài hình ảnh không có phần đệm, tôi cũng muốn có thể dễ dàng thêm chú thích, v.v., ngoài một cốt truyện hình ảnh đơn giản.

Vì vậy, những gì tôi đã làm là kết hợp câu trả lời của David với csneme ' để tạo ra một trình bao bọc đơn giản tại thời điểm tạo hình. Khi bạn sử dụng điều đó, bạn không cần bất kỳ thay đổi nào sau đó với imsave () hoặc bất cứ điều gì khác:

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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.