บันทึกพล็อตไปยังไฟล์ภาพแทนการแสดงโดยใช้ Matplotlib


1150

ฉันกำลังเขียนสคริปต์ที่รวดเร็วและสกปรกเพื่อสร้างแปลงได้อย่างรวดเร็ว ฉันใช้รหัสด้านล่าง (จากเอกสารMatplotlib ) เป็นจุดเริ่มต้น:

from pylab import figure, axes, pie, title, show

# Make a square figure and axes
figure(1, figsize=(6, 6))
ax = axes([0.1, 0.1, 0.8, 0.8])

labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
fracs = [15, 30, 45, 10]

explode = (0, 0.05, 0, 0)
pie(fracs, explode=explode, labels=labels, autopct='%1.1f%%', shadow=True)
title('Raining Hogs and Dogs', bbox={'facecolor': '0.8', 'pad': 5})

show()  # Actually, don't show, just save to foo.png

ฉันไม่ต้องการแสดงพล็อตบน GUI แทนฉันต้องการบันทึกพล็อตไปยังไฟล์ (เช่น foo.png) เพื่อให้สามารถใช้พล็อตสคริปต์ในแบตช์สคริปต์ได้ ฉันจะทำอย่างไร


84
ดูเหมือนว่าฉันพบคำตอบ: มัน pylab.savefig ('foo.png')
Homunculus Reticulli

2
ลิงก์ควรลิงก์ไปยังที่อื่นใน matplotlib.org หรือไม่
A.

40
นอกจากนี้หากไม่ได้ใช้ pylab วัตถุรูปก็มีsavefigวิธีการเช่นกัน เพื่อให้คุณสามารถโทรหาแล้วfig = plt.figure() fig.savefig(...)
A.

27
คำตอบหลายข้อพูดถึงหน้าplt.close(fig)ซึ่งมีความสำคัญอย่างยิ่งในลูปใหญ่ มิฉะนั้นตัวเลขจะยังคงเปิดอยู่และรออยู่ในหน่วยความจำและตัวเลขที่เปิดอยู่ทั้งหมดจะแสดงเมื่อทำการประมวลผลplt.show()
timctran

nb: matplotlib.pyplot เป็นที่ต้องการ: stackoverflow.com/questions/11469336/…
ErichBSchulz

คำตอบ:


1438

ขณะที่คำถามที่ได้รับการตอบรับฉันต้องการที่จะเพิ่มประโยชน์บางเคล็ดลับเมื่อใช้matplotlib.pyplot.savefig รูปแบบไฟล์สามารถระบุได้โดยส่วนขยาย:

from matplotlib import pyplot as plt

plt.savefig('foo.png')
plt.savefig('foo.pdf')

จะให้เอาต์พุต rasterized หรือ vectorized ตามลำดับซึ่งทั้งสองอาจเป็นประโยชน์ นอกจากนี้คุณจะพบว่าpylabมีพื้นที่ว่างรอบ ๆ ภาพที่ใจกว้างและไม่พึงปรารถนา ลบออกด้วย:

savefig('foo.png', bbox_inches='tight')

9
เป็นไปได้หรือไม่ที่จะเปลี่ยนขนาดของภาพที่ได้
Llamageddon

43
@Asmageddon ในplt.savefigคุณสามารถเปลี่ยน dpi ดูลิงค์ในคำตอบ ขนาดสามารถควบคุมได้เมื่อสร้างรูปให้ดูfigsizeในmatplotlib.org/api/figure_api.html#matplotlib.figure.Figure
ติดยาเสพติด

5
@Mochsge คุณสามารถโทรหาplt.ioff()ซึ่งควรปิดการใช้งานการโต้ตอบในmatplotlib.pyplotคำสั่ง
rubenvb

5
@STMohammed foo.png เป็นเส้นทาง savefig("mydir/foo.png")คุณสามารถยกตัวอย่างเช่นใส่ไว้ในไดเรกทอรีเช่นนี้
ติดยาเสพติด

3
bbox_inches = 'tight' ทำงานเหมือนมีเสน่ห์ คุณทำให้วันของฉัน
Catbuilts

205

อย่างที่คนอื่น ๆ พูดกันplt.savefig()หรือfig1.savefig()เป็นวิธีการบันทึกภาพ

แต่ผมพบว่าในบางกรณีรูปที่จะแสดงให้เห็นเสมอ (เช่นกับ Spyder ที่มีplt.ion(): โหมดโต้ตอบ = เปิด) ฉันทำงานนี้โดยบังคับให้ปิดหน้าต่างรูปในลูปยักษ์ของฉันด้วยplt.close(figure_object)(ดูเอกสาร ) ดังนั้นฉันจึงไม่มีตัวเลขเปิดหนึ่งล้านในระหว่างวง:

import matplotlib.pyplot as plt
fig, ax = plt.subplots( nrows=1, ncols=1 )  # create figure & 1 axis
ax.plot([0,1,2], [10,20,3])
fig.savefig('path/to/save/image/to.png')   # save the figure to file
plt.close(fig)    # close the figure window

คุณควรจะสามารถเปิดภาพในภายหลังได้หากจำเป็นด้วยfig.show()(ไม่ได้ทดสอบตัวเอง)


9
คุณสามารถตั้งค่าได้plt.ioff() # turn of interactive plotting modeเช่นกัน แต่นั่นอาจปิดการทำงานที่คุณต้องการใช้หากรหัสของคุณออกโดยมีข้อผิดพลาด
มิส

2
คุณจะเห็นปัญหาเดียวกันในสมุดบันทึก Jupyter plt.close(fig)แก้ไขได้
intsco


89

เพิ่งพบลิงค์นี้ในเอกสาร MatPlotLib ที่อยู่ตรงประเด็นนี้: http://matplotlib.org/faq/howto_faq.html#generate-images-without-having-a-window-appear

พวกเขาบอกว่าวิธีที่ง่ายที่สุดในการป้องกันไม่ให้ร่างโผล่ขึ้นมาคือใช้แบ็กเอนด์ที่ไม่มีการโต้ตอบ (เช่น Agg) ผ่านmatplotib.use(<backend>)เช่น:

import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
plt.plot([1,2,3])
plt.savefig('myfig')

ฉันยังต้องการใช้เป็นการส่วนตัวplt.close( fig )ตั้งแต่นั้นคุณมีตัวเลือกเพื่อซ่อนตัวเลขบางอย่าง (ในระหว่างการวนซ้ำ) แต่ยังคงแสดงตัวเลขสำหรับการประมวลผลข้อมูลหลังการวนซ้ำ มันอาจช้ากว่าการเลือกแบ็กเอนด์ที่ไม่มีการโต้ตอบแม้ว่าจะน่าสนใจถ้ามีคนทดสอบเรื่องนั้น

UPDATE : สำหรับ Spyder คุณจะไม่สามารถตั้งค่าแบ็กเอนด์ด้วยวิธีนี้ได้ (เนื่องจาก Spyder มักจะโหลด matplotlib ก่อนทำให้ไม่สามารถใช้งานได้matplotlib.use())

ให้ใช้plt.switch_backend('Agg')หรือปิด " เปิดใช้งานการสนับสนุน " ใน Spyder prefs และรันmatplotlib.use('Agg')คำสั่งด้วยตัวเอง

จากทั้งสองคำแนะนำ: หนึ่ง , สอง


1
วิธีนี้ใช้งานได้ดีสำหรับสถานการณ์ที่คุณไม่มีจอแสดงผล การใช้แบ็กเอนด์อื่นด้วย.plot()จะทำให้เกิดข้อผิดพลาดหากos.environ['DISPLAY']ไม่ได้ตั้งอย่างถูกต้อง
เศรษฐกิจ

1
ขอบคุณ การทำงานนี้และมีประโยชน์มากสำหรับเซิร์ฟเวอร์ที่ใช้งานจริงซึ่งไม่มีการเชื่อมต่ออินเทอร์เน็ตและต้องการให้ผู้ดูแลระบบติดตั้งแพ็คเกจใด ๆ
Leon

ฉันชอบการกวดวิชาเว็บไซต์ matplotlib มีคำอธิบาย / คำจำกัดความของ "แบ็กเอนด์": matplotlib.org/tutorials/introductory/ …
แทนเนอร์สตราก์

47

หากคุณไม่ชอบแนวคิดของตัวเลข "ปัจจุบัน" ให้ทำ:

import matplotlib.image as mpimg

img = mpimg.imread("src.png")
mpimg.imsave("out.png", img)

2
นี่ไม่ใช่แค่คัดลอกsrc.pngไปที่out.pngใช่ไหม
gerrit

นี่เป็นเพียงตัวอย่างที่แสดงว่าคุณมีวัตถุรูปภาพ ( img) จากนั้นคุณสามารถบันทึกลงในไฟล์ด้วย.imsave()วิธีการ
wonder.mice

4
@ wonder.mice จะช่วยแสดงวิธีการสร้างภาพโดยไม่ใช้ตัวเลขปัจจุบัน
Scry

@ wonder.mice ขอบคุณสำหรับตัวอย่างนี้มันเป็นอันแรกที่แสดงให้ฉันเห็นวิธีการบันทึกวัตถุรูปภาพเป็น. png
Arthur Dent

@scry คุณไม่จำเป็นต้องสร้างภาพเสมอบางครั้งคุณลองใช้โค้ดและต้องการเอาท์พุทแบบเห็นภาพมันมีประโยชน์ในบางโอกาส
Schütze

29

คำตอบอื่น ๆ นั้นถูกต้อง อย่างไรก็ตามบางครั้งฉันพบว่าฉันต้องการเปิดวัตถุรูปในภายหลัง ตัวอย่างเช่นฉันอาจต้องการเปลี่ยนขนาดฉลากเพิ่มกริดหรือทำการประมวลผลอื่น ๆ ในโลกที่สมบูรณ์แบบฉันเพียงแค่รันรหัสอีกครั้งเพื่อสร้างพล็อตและปรับการตั้งค่า อนิจจาโลกไม่สมบูรณ์แบบ ดังนั้นนอกเหนือจากการบันทึกเป็น PDF หรือ PNG ฉันเพิ่ม:

with open('some_file.pkl', "wb") as fp:
    pickle.dump(fig, fp, protocol=4)

เช่นนี้ฉันสามารถโหลดวัตถุรูปและจัดการการตั้งค่าตามที่ฉันต้องการได้ในภายหลัง

ฉันยังเขียนสแต็กด้วยซอร์สโค้ดและlocals()พจนานุกรมสำหรับแต่ละฟังก์ชัน / วิธีในสแต็กเพื่อที่ฉันจะสามารถบอกได้ในภายหลังว่าสิ่งใดที่สร้างตัวเลขขึ้นมา

หมายเหตุ: โปรดระวังบางครั้งวิธีนี้จะสร้างไฟล์ขนาดใหญ่


การพัฒนาในโน๊ตบุ๊ค jupyter จะไม่ง่ายกว่าไหมถ้ามีตัวเลขในบรรทัด? วิธีนี้คุณสามารถติดตามประวัติและเรียกใช้ซ้ำได้อย่างแม่นยำ
Ciprian Tomoiagă

3
@CiprianTomoiaga ฉันไม่เคยสร้างแผนการผลิตจากเปลือก Python แบบโต้ตอบ (Jupyter หรืออย่างอื่น) ฉันพล็อตทั้งหมดจากสคริปต์
gerrit

28
import datetime
import numpy as np
from matplotlib.backends.backend_pdf import PdfPages
import matplotlib.pyplot as plt

# Create the PdfPages object to which we will save the pages:
# The with statement makes sure that the PdfPages object is closed properly at
# the end of the block, even if an Exception occurs.
with PdfPages('multipage_pdf.pdf') as pdf:
    plt.figure(figsize=(3, 3))
    plt.plot(range(7), [3, 1, 4, 1, 5, 9, 2], 'r-o')
    plt.title('Page One')
    pdf.savefig()  # saves the current figure into a pdf page
    plt.close()

    plt.rc('text', usetex=True)
    plt.figure(figsize=(8, 6))
    x = np.arange(0, 5, 0.1)
    plt.plot(x, np.sin(x), 'b-')
    plt.title('Page Two')
    pdf.savefig()
    plt.close()

    plt.rc('text', usetex=False)
    fig = plt.figure(figsize=(4, 5))
    plt.plot(x, x*x, 'ko')
    plt.title('Page Three')
    pdf.savefig(fig)  # or you can pass a Figure object to pdf.savefig
    plt.close()

    # We can also set the file's metadata via the PdfPages object:
    d = pdf.infodict()
    d['Title'] = 'Multipage PDF Example'
    d['Author'] = u'Jouni K. Sepp\xe4nen'
    d['Subject'] = 'How to create a multipage pdf file and set its metadata'
    d['Keywords'] = 'PdfPages multipage keywords author title subject'
    d['CreationDate'] = datetime.datetime(2009, 11, 13)
    d['ModDate'] = datetime.datetime.today()

28

หลังจากใช้พล็อต () และฟังก์ชั่นอื่น ๆ เพื่อสร้างเนื้อหาที่คุณต้องการคุณสามารถใช้ประโยคเช่นนี้เพื่อเลือกระหว่างการพล็อตหน้าจอหรือไฟล์:

import matplotlib.pyplot as plt

fig = plt.figure(figsize=(4, 5))       # size in inches
# use plot(), etc. to create your plot.

# Pick one of the following lines to uncomment
# save_file = None
# save_file = os.path.join(your_directory, your_file_name)  

if save_file:
    plt.savefig(save_file)
    plt.close(fig)
else:
    plt.show()

บางคนบอกว่าfig = plt.figure(figuresize=4, 5)อาจเป็นfig = plt.figure(figsize=(4, 5)) #figure sizes in inches
ผู้ใช้

24

ฉันใช้สิ่งต่อไปนี้:

import matplotlib.pyplot as plt

p1 = plt.plot(dates, temp, 'r-', label="Temperature (celsius)")  
p2 = plt.plot(dates, psal, 'b-', label="Salinity (psu)")  
plt.legend(loc='upper center', numpoints=1, bbox_to_anchor=(0.5, -0.05),        ncol=2, fancybox=True, shadow=True)

plt.savefig('data.png')  
plt.show()  
f.close()
plt.close()

ฉันพบว่าสำคัญมากที่จะใช้ plt.show หลังจากบันทึกรูปไม่เช่นนั้นจะไม่ทำงาน รูปที่ส่งออกเป็น png


2
ขออภัยนี่คืออะไร แปลงไฟล์ภาพ? f= plt.savefig('data.png')
มอร์ส

14

คุณสามารถทำได้:

plt.show(hold=False)
plt.savefig('name.pdf')

และอย่าลืมให้ savefig เสร็จสิ้นก่อนที่จะปิดพล็อต GUI วิธีนี้คุณสามารถดูภาพล่วงหน้า

หรือคุณสามารถมองไปที่มันมีplt.show() แล้วปิด GUI และเรียกใช้สคริปต์อีกครั้ง แต่คราวนี้แทนที่ด้วยplt.show()plt.savefig()

หรือคุณสามารถใช้

fig, ax = plt.figure(nrows=1, ncols=1)
plt.plot(...)
plt.show()
fig.savefig('out.pdf')

2
ได้รับการโต้แย้งคำหลักที่ไม่คาดคิด 'ถือ'
amitdatta

13

ถ้าเช่นฉันคุณใช้ Spyder IDE คุณต้องปิดใช้งานโหมดการโต้ตอบด้วย:

plt.ioff()

(คำสั่งนี้จะเริ่มต้นโดยอัตโนมัติเมื่อเริ่มต้นทางวิทยาศาสตร์)

หากคุณต้องการเปิดใช้งานอีกครั้งให้ใช้:

plt.ion()


12

การแก้ไขปัญหา :

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
matplotlib.style.use('ggplot')
ts = pd.Series(np.random.randn(1000), index=pd.date_range('1/1/2000', periods=1000))
ts = ts.cumsum()
plt.figure()
ts.plot()
plt.savefig("foo.png", bbox_inches='tight')

หากคุณต้องการแสดงภาพรวมทั้งการบันทึกการใช้ภาพ:

%matplotlib inline

หลังจาก import matplotlib


9

ตามที่ถามMatplotlib (pyplot) savefig ผลภาพว่างเปล่า

สิ่งหนึ่งที่ควรทราบ: ถ้าคุณใช้plt.showและควรหลังจากplt.savefigหรือคุณจะให้ภาพเปล่า

ตัวอย่างรายละเอียด:

import numpy as np
import matplotlib.pyplot as plt


def draw_result(lst_iter, lst_loss, lst_acc, title):
    plt.plot(lst_iter, lst_loss, '-b', label='loss')
    plt.plot(lst_iter, lst_acc, '-r', label='accuracy')

    plt.xlabel("n iteration")
    plt.legend(loc='upper left')
    plt.title(title)
    plt.savefig(title+".png")  # should before plt.show method

    plt.show()


def test_draw():
    lst_iter = range(100)
    lst_loss = [0.01 * i + 0.01 * i ** 2 for i in xrange(100)]
    # lst_loss = np.random.randn(1, 100).reshape((100, ))
    lst_acc = [0.01 * i - 0.01 * i ** 2 for i in xrange(100)]
    # lst_acc = np.random.randn(1, 100).reshape((100, ))
    draw_result(lst_iter, lst_loss, lst_acc, "sgd_method")


if __name__ == '__main__':
    test_draw()

ป้อนคำอธิบายรูปภาพที่นี่


6
import matplotlib.pyplot as plt
plt.savefig("image.png")

ใน Jupyter Notebook คุณจะต้องลบplt.show()และเพิ่มplt.savefig()พร้อมกับส่วนที่เหลือของรหัส plt ในเซลล์เดียว ภาพจะยังคงปรากฏในสมุดบันทึกของคุณ


1
"remove plt.show ()" .. สิ่งนี้ช่วยวันของฉัน ...
Guru

4

ระบุว่าในวันนี้ (ไม่สามารถใช้ได้เมื่อคำถามนี้ถูกสร้างขึ้น) ผู้คนจำนวนมากใช้ Jupyter โน๊ตบุ๊คเป็นคอนโซลหลามมีวิธีที่ง่ายมากที่จะบันทึกแปลงเป็น.pngเพียงแค่เรียกmatplotlib's pylabระดับจาก Jupyter โน๊ตบุ๊ค, พล็อตร่าง' อินไลน์ 'เซลล์ jupyter แล้วลากรูป / ภาพนั้นไปยังไดเรกทอรีท้องถิ่น อย่าลืม %matplotlib inlineในบรรทัดแรก!


1
เป็นความคิดที่ดีเพียงแค่ต้องจดบันทึกผลกระทบที่เกิดขึ้นกับขนาดไฟล์ถ้าภาพถูกปล่อยให้ฝังอยู่ในสมุดบันทึก ..
รัสเซีย

3

นอกจากนี้ข้างต้นฉันเพิ่ม__file__ชื่อเพื่อให้รูปภาพและไฟล์ Python ได้รับชื่อเดียวกัน ฉันยังเพิ่มข้อโต้แย้งเล็กน้อยเพื่อทำให้ดูดีขึ้น:

# Saves a PNG file of the current graph to the folder and updates it every time
# (nameOfimage, dpi=(sizeOfimage),Keeps_Labels_From_Disappearing)
plt.savefig(__file__+".png",dpi=(250), bbox_inches='tight')
# Hard coded name: './test.png'

2

เมื่อใช้matplotlib.pyplotงานคุณต้องบันทึกแผนของคุณก่อนแล้วจึงปิดโดยใช้ 2 บรรทัดเหล่านี้:

fig.savefig('plot.png') # save the plot, place the path you want to save the figure in quotation
plt.close(fig) # close the figure window

1

ตามที่แนะนำไว้ก่อนหน้านี้คุณสามารถใช้:

import matplotlib.pyplot as plt
plt.savefig("myfig.png")

สำหรับการบันทึกอิมเมจ IPhython ที่คุณกำลังแสดง หรือบันทึกย่ออื่น (มองจากมุมที่แตกต่าง) หากคุณเคยทำงานกับ open cv หรือถ้าคุณนำเข้า cv เปิดคุณสามารถไปที่:

นำเข้า cv2

cv2.imwrite ( "myfig.png" ภาพ)

แต่นี่เป็นเพียงในกรณีที่คุณจำเป็นต้องทำงานกับ Open CV มิฉะนั้น plt.savefig () ควรเพียงพอ


0

คุณสามารถบันทึกรูปภาพของคุณด้วยส่วนขยายใด ๆ (png, jpg ฯลฯ ) และด้วยความละเอียดที่คุณต้องการ นี่คือฟังก์ชั่นเพื่อบันทึกรูปของคุณ

import os

def save_fig(fig_id, tight_layout=True, fig_extension="png", resolution=300):
    path = os.path.join(IMAGES_PATH, fig_id + "." + fig_extension)
    print("Saving figure", fig_id)
    if tight_layout:
        plt.tight_layout()
    plt.savefig(path, format=fig_extension, dpi=resolution)

'fig_id' เป็นชื่อที่คุณต้องการบันทึกรูปของคุณ หวังว่าจะช่วย :)


0

คุณสามารถทำได้เช่นนี้:

def plotAFig():
  plt.figure()
  plt.plot(x,y,'b-')
  plt.savefig("figurename.png")
  plt.close()
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.