Có cách nào để tách các lô matplotlib để việc tính toán có thể tiếp tục không?


258

Sau các hướng dẫn này trong trình thông dịch Python, người ta sẽ nhận được một cửa sổ với một âm mưu:

from matplotlib.pyplot import *
plot([1,2,3])
show()
# other code

Thật không may, tôi không biết làm thế nào để tiếp tục khám phá tương tác con số được tạo bởi show() trong khi chương trình thực hiện các tính toán tiếp theo.

Có thể ở tất cả? Đôi khi các tính toán dài và sẽ có ích nếu chúng được tiến hành trong quá trình kiểm tra kết quả trung gian.


5
Tôi không thể xác nhận rằng giải pháp được chọn từ nosklo vào ngày 16:51 đang hoạt động. Đối với tôi vẽ không mở một cửa sổ để hiển thị cốt truyện, chỉ có chương trình chặn ở cuối hiển thị giải pháp. Tuy nhiên, trả lời của ông từ 17:00 là chính xác. Bật chế độ tương tác thông qua ion()sửa lỗi.
H. Brandmeier

nếu bạn là một lập trình viên tiên tiến, bạn có thể sử dụng os.fork()nhưng hãy nhớ rằng việc sử dụng os.fork()có thể khó khăn vì bạn đang tạo ra một quy trình mới bằng cách sao chép quy trình cũ.
Trevor Boyd Smith

Câu trả lời:


214

Sử dụng matplotlib các cuộc gọi sẽ không chặn:

Sử dụng draw():

from matplotlib.pyplot import plot, draw, show
plot([1,2,3])
draw()
print 'continue computation'

# at the end call show to ensure window won't close.
show()

Sử dụng chế độ tương tác:

from matplotlib.pyplot import plot, ion, show
ion() # enables interactive mode
plot([1,2,3]) # result shows immediatelly (implicit draw())

print 'continue computation'

# at the end call show to ensure window won't close.
show()

28
Với matplotlib 0.98.3, nhập đúng là từ lô nhập matplotlib.pyplot, vẽ, hiển thị
meteore

112
draw()không làm việc cho tôi, nó không mở bất kỳ cửa sổ nào. Tuy nhiên, sử dụng show(block=False)thay vì draw()dường như thực hiện thủ thuật trong matplotlib 1.1.
rumpel

4
@nosklo, bạn đã thấy chưa? Bạn đã biến nó thành một hướng dẫn
ngày

4
@noskolo nếu tôi có một vài hình, làm thế nào để vẽ và hiển thị Fig1 trong khi tiếp tục nền để tiếp tục? Tôi muốn con số này được mở cho đến khi con số tiếp theo được tạo ra, vì vậy cuối cùng tôi đã mở tất cả các trái vả và mã được hoàn thành. Với giải pháp hiện tại của bạn, nó khiến tôi chờ đợi để đóng Fig1 và sau đó mã tiếp tục. Cảm ơn!!
vật lý trị liệu

9
draw()cũng không làm việc cho tôi, chỉ pause(0.001)làm: stackoverflow.com/questions/28269157/
Khăn

133

Sử dụng từ khóa 'chặn' để ghi đè hành vi chặn, ví dụ:

from matplotlib.pyplot import show, plot

plot(1)  
show(block=False)

# your code

để tiếp tục mã của bạn.


17
nhưng điều này sẽ đóng cửa sổ cốt truyện ngay lập tức, sẽ không giữ cho cốt truyện mở.
LWZ

8
Vâng, điều đó đúng nếu bạn gọi tập lệnh của mình từ dòng lệnh. Nếu bạn ở trong vỏ Ipython, cửa sổ sẽ không bị đóng.
Jan

1
kiểm tra câu trả lời của @Nico để biết một mẹo sẽ để mở cửa sổ trong trường hợp chung.
Ngày

2
Đối với tôi, điều này không đóng cửa sổ ngay lập tức, chỉ khi tập lệnh kết thúc (vì vậy bạn có thể chặn thủ công ở cuối tập lệnh nếu bạn muốn nó mở).
luator

Có, các cửa sổ không bị chặn sẽ đóng khi thoát khỏi tập lệnh . Bạn có thể (a) cho phép chặn trên âm mưu cuối cùng của mình hoặc (b) không thoát khỏi tập lệnh (có thể yêu cầu nhập liệu: "nhấn <Enter> để thoát âm mưu" hoặc đại loại như thế).
Daniel Goldfarb

29

Tốt hơn là luôn luôn kiểm tra với thư viện bạn đang sử dụng nếu nó hỗ trợ việc sử dụng không chặn .

Nhưng nếu bạn muốn một giải pháp chung chung hơn hoặc nếu không có cách nào khác, bạn có thể chạy bất cứ thứ gì chặn trong một quy trình riêng biệt bằng cách sử dụng multprocessingmô-đun có trong python. Tính toán sẽ tiếp tục:

from multiprocessing import Process
from matplotlib.pyplot import plot, show

def plot_graph(*args):
    for data in args:
        plot(data)
    show()

p = Process(target=plot_graph, args=([1, 2, 3],))
p.start()

print 'yay'
print 'computation continues...'
print 'that rocks.'

print 'Now lets wait for the graph be closed to continue...:'
p.join()

Điều đó có chi phí cao trong việc khởi chạy một quy trình mới và đôi khi khó gỡ lỗi hơn trong các tình huống phức tạp, vì vậy tôi thích giải pháp khác (sử dụng matplotlibcác lệnh gọi API không chặn )


Cảm ơn! Vì tôi chưa có Python 2.6 trên hệ thống của mình, tôi đã sử dụng luồng. Điều này thay thế cho Quá trình. Tôi quan sát thấy rằng các báo cáo in tiếp theo trở nên chậm không chịu nổi (lần in thứ ba, tôi đã phát hành KeyboardInterrupt sau 1 phút chờ đợi). Đây có phải là một hiệu ứng của việc sử dụng luồng thay vì đa xử lý?
meteore

@meteore: Vâng, luồng hút. Bạn luôn có thể nhận được đa xử lý cho python <2.6 từ đây: py Xử lý.berlios.de
nosklo

Điều này là hoàn toàn xuất sắc. Bạn có biết tại sao các câu lệnh in không được thực thi khi ở Emacs (chế độ python) cho đến khi cửa sổ cốt truyện được đóng lại không?
meteore

Trong Ubuntu 8.10 (Intrepid), gói (cho python <2.6) được gọi là xử lý python và bạn nhập nó với 'nhập xử lý'
meteore

1
Bạn đã không bỏ lỡ if __name__ == '__main__':?
Wernight

25

Thử

import matplotlib.pyplot as plt
plt.plot([1,2,3])
plt.show(block=False)
# other code
# [...]

# Put
plt.show()
# at the very end of your script to make sure Python doesn't bail out
# before you finished examining.

Các show()tài liệu nói:

Trong chế độ không tương tác, hiển thị tất cả các số liệu và chặn cho đến khi các số liệu đã được đóng lại; trong chế độ tương tác, nó không có hiệu lực trừ khi các số liệu được tạo trước khi thay đổi từ chế độ không tương tác sang chế độ tương tác (không được khuyến nghị). Trong trường hợp đó, nó sẽ hiển thị các số liệu nhưng không chặn.

Một đối số từ khóa thử nghiệm, chặn, có thể được đặt thành Đúng hoặc Sai để ghi đè hành vi chặn được mô tả ở trên.


tại sao không sử dụng draw (); [mã khác]; chỉ() ? Theo như tôi biết thì khối = Sai đã bị phản đối
Bogdan

Tại sao bạn nghĩ nó bị phản đối? Tôi thấy nó được ghi lại ở đây .
Nico Schlömer

11

QUAN TRỌNG : Chỉ để làm cho một cái gì đó rõ ràng. Tôi giả sử rằng các lệnh nằm trong một .pytập lệnh và tập lệnh được gọi bằng cách sử dụng ví dụ python script.pytừ bàn điều khiển.

Một cách đơn giản phù hợp với tôi là:

  1. Sử dụng khối = Sai bên trong chương trình: plt.show (khối = Sai)
  2. Sử dụng một chương trình khác () ở cuối tập lệnh .py.

Ví dụ về script.py tập tin:

plt.imshow(*something*)                                                               
plt.colorbar()                                                                             
plt.xlabel("true ")                                                                   
plt.ylabel("predicted ")                                                              
plt.title(" the matrix")  

# Add block = False                                           
plt.show(block = False)

################################
# OTHER CALCULATIONS AND CODE HERE ! ! !
################################

# the next command is the last line of my script
plt.show()



8

Trong trường hợp của tôi, tôi muốn có một số cửa sổ bật lên khi chúng đang được tính toán. Để tham khảo, đây là cách:

from matplotlib.pyplot import draw, figure, show
f1, f2 = figure(), figure()
af1 = f1.add_subplot(111)
af2 = f2.add_subplot(111)
af1.plot([1,2,3])
af2.plot([6,5,4])
draw() 
print 'continuing computation'
show()

Tái bút Một hướng dẫn khá hữu ích cho giao diện OO của matplotlib .


6

Chà, tôi đã gặp khó khăn lớn khi tìm ra các lệnh không chặn ... Nhưng cuối cùng, tôi đã tìm cách làm lại ví dụ " Cookbook / Matplotlib / Animations - Hoạt hình các yếu tố cốt truyện được chọn ", để nó hoạt động với các luồng ( và truyền dữ liệu giữa các luồng thông qua các biến toàn cục hoặc thông qua đa xử lýPipe ) trên Python 2.6.5 trên Ubuntu 10.04.

Tập lệnh có thể được tìm thấy ở đây: Animating_selected_plot_elements-thread.py - nếu không thì dán bên dưới ( với ít bình luận hơn ) để tham khảo:

import sys
import gtk, gobject
import matplotlib
matplotlib.use('GTKAgg')
import pylab as p
import numpy as nx 
import time

import threading 



ax = p.subplot(111)
canvas = ax.figure.canvas

# for profiling
tstart = time.time()

# create the initial line
x = nx.arange(0,2*nx.pi,0.01)
line, = ax.plot(x, nx.sin(x), animated=True)

# save the clean slate background -- everything but the animated line
# is drawn and saved in the pixel buffer background
background = canvas.copy_from_bbox(ax.bbox)


# just a plain global var to pass data (from main, to plot update thread)
global mypass

# http://docs.python.org/library/multiprocessing.html#pipes-and-queues
from multiprocessing import Pipe
global pipe1main, pipe1upd
pipe1main, pipe1upd = Pipe()


# the kind of processing we might want to do in a main() function,
# will now be done in a "main thread" - so it can run in
# parallel with gobject.idle_add(update_line)
def threadMainTest():
    global mypass
    global runthread
    global pipe1main

    print "tt"

    interncount = 1

    while runthread: 
        mypass += 1
        if mypass > 100: # start "speeding up" animation, only after 100 counts have passed
            interncount *= 1.03
        pipe1main.send(interncount)
        time.sleep(0.01)
    return


# main plot / GUI update
def update_line(*args):
    global mypass
    global t0
    global runthread
    global pipe1upd

    if not runthread:
        return False 

    if pipe1upd.poll(): # check first if there is anything to receive
        myinterncount = pipe1upd.recv()

    update_line.cnt = mypass

    # restore the clean slate background
    canvas.restore_region(background)
    # update the data
    line.set_ydata(nx.sin(x+(update_line.cnt+myinterncount)/10.0))
    # just draw the animated artist
    ax.draw_artist(line)
    # just redraw the axes rectangle
    canvas.blit(ax.bbox)

    if update_line.cnt>=500:
        # print the timing info and quit
        print 'FPS:' , update_line.cnt/(time.time()-tstart)

        runthread=0
        t0.join(1)   
        print "exiting"
        sys.exit(0)

    return True



global runthread

update_line.cnt = 0
mypass = 0

runthread=1

gobject.idle_add(update_line)

global t0
t0 = threading.Thread(target=threadMainTest)
t0.start() 

# start the graphics update thread
p.show()

print "out" # will never print - show() blocks indefinitely! 

Hy vọng điều này sẽ giúp ai đó,
Chúc mừng!


5

Trong nhiều trường hợp sẽ thuận tiện hơn cho đến khi lưu hình ảnh dưới dạng tệp .png trên ổ cứng. Đây là lý do tại sao:

Ưu điểm:

  • Bạn có thể mở nó, xem nó và đóng nó bất cứ lúc nào trong quá trình. Điều này đặc biệt thuận tiện khi ứng dụng của bạn chạy trong một thời gian dài.
  • Không có gì bật lên và bạn không bị buộc phải mở cửa sổ. Điều này đặc biệt thuận tiện khi bạn đang xử lý nhiều số liệu.
  • Hình ảnh của bạn có thể truy cập để tham khảo sau này và không bị mất khi đóng cửa sổ hình.

Hạn chế:

  • Điều duy nhất tôi có thể nghĩ là bạn sẽ phải đi tìm thư mục và tự mở hình ảnh.

Nếu bạn đang cố gắng tạo ra nhiều hình ảnh, tôi chân thành đồng ý.
tưởng tượng

6
Các png rút lại không tương tác: \
Nghịch đảo

5

Nếu bạn đang làm việc trong bảng điều khiển, tức là IPythonbạn có thể sử dụng plt.show(block=False)như được chỉ ra trong các câu trả lời khác. Nhưng nếu bạn lười biếng, bạn chỉ cần gõ:

plt.show(0)

Mà sẽ giống nhau.


5

Tôi cũng đã phải thêm plt.pause(0.001)vào mã của mình để thực sự làm cho nó hoạt động bên trong một vòng lặp for (nếu không nó sẽ chỉ hiển thị cốt truyện đầu tiên và cuối cùng):

import matplotlib.pyplot as plt

plt.scatter([0], [1])
plt.draw()
plt.show(block=False)

for i in range(10):
    plt.scatter([i], [i+1])
    plt.draw()
    plt.pause(0.001)

Điều này đã làm việc với tôi với matplotlib3 trên macOS. Tuyệt quá!
Jerry Ma

4

Trên hệ thống của tôi, chương trình của tôi không chặn, mặc dù tôi muốn tập lệnh chờ người dùng tương tác với biểu đồ (và thu thập dữ liệu bằng cách sử dụng các cuộc gọi lại 'pick_event') trước khi tiếp tục.

Để chặn thực thi cho đến khi cửa sổ cốt truyện được đóng lại, tôi đã sử dụng như sau:

fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.plot(x,y)

# set processing to continue when window closed
def onclose(event):
    fig.canvas.stop_event_loop()
fig.canvas.mpl_connect('close_event', onclose)

fig.show() # this call does not block on my system
fig.canvas.start_event_loop_default() # block here until window closed

# continue with further processing, perhaps using result from callbacks

Tuy nhiên, lưu ý rằng canvas.start_event_loop_default () tạo ra cảnh báo sau:

C:\Python26\lib\site-packages\matplotlib\backend_bases.py:2051: DeprecationWarning: Using default event loop until function specific to this GUI is implemented
  warnings.warn(str,DeprecationWarning)

mặc dù kịch bản vẫn chạy.


Cảm ơn bạn! Spyder nhập -pylab khi khởi động thường hữu ích, nhưng có nghĩa là show () sẽ không chặn khi ioff () - điều này cho phép bạn khắc phục hành vi này!
mất

3

Tôi cũng muốn các ô của mình hiển thị chạy phần còn lại của mã (và sau đó tiếp tục hiển thị) ngay cả khi có lỗi (đôi khi tôi sử dụng các ô để gỡ lỗi). Tôi đã mã hóa bản hack nhỏ này để bất kỳ âm mưu nào trong withcâu lệnh này hoạt động như vậy.

Điều này có lẽ là một chút quá không chuẩn và không nên cho mã sản xuất. Có lẽ có rất nhiều "gotchas" ẩn trong mã này.

from contextlib import contextmanager

@contextmanager
def keep_plots_open(keep_show_open_on_exit=True, even_when_error=True):
    '''
    To continue excecuting code when plt.show() is called
    and keep the plot on displaying before this contex manager exits
    (even if an error caused the exit).
    '''
    import matplotlib.pyplot
    show_original = matplotlib.pyplot.show
    def show_replacement(*args, **kwargs):
        kwargs['block'] = False
        show_original(*args, **kwargs)
    matplotlib.pyplot.show = show_replacement

    pylab_exists = True
    try:
        import pylab
    except ImportError: 
        pylab_exists = False
    if pylab_exists:
        pylab.show = show_replacement

    try:
        yield
    except Exception, err:
        if keep_show_open_on_exit and even_when_error:
            print "*********************************************"
            print "Error early edition while waiting for show():" 
            print "*********************************************"
            import traceback
            print traceback.format_exc()
            show_original()
            print "*********************************************"
            raise
    finally:
        matplotlib.pyplot.show = show_original
        if pylab_exists:
            pylab.show = show_original
    if keep_show_open_on_exit:
        show_original()

# ***********************
# Running example
# ***********************
import pylab as pl
import time
if __name__ == '__main__':
    with keep_plots_open():
        pl.figure('a')
        pl.plot([1,2,3], [4,5,6])     
        pl.plot([3,2,1], [4,5,6])
        pl.show()

        pl.figure('b')
        pl.plot([1,2,3], [4,5,6])
        pl.show()

        time.sleep(1)
        print '...'
        time.sleep(1)
        print '...'
        time.sleep(1)
        print '...'
        this_will_surely_cause_an_error

Nếu / khi tôi thực hiện đúng "giữ cho các ô mở (ngay cả khi xảy ra lỗi) và cho phép các ô mới được hiển thị", tôi muốn tập lệnh thoát đúng nếu không có sự can thiệp nào của người dùng nói với nó (cho mục đích thực thi hàng loạt).

Tôi có thể sử dụng một cái gì đó giống như câu hỏi hết thời gian "Kết thúc tập lệnh! \ NPNhấn p nếu bạn muốn tạm dừng đầu ra âm mưu (bạn có 5 giây):" từ /programming/26704840/corner -case-for-my-chờ-cho-người dùng-đầu vào-gián đoạn-thực hiện .


2
plt.figure(1)
plt.imshow(your_first_image)

plt.figure(2)
plt.imshow(your_second_image)

plt.show(block=False) # That's important 

raw_input("Press ENTER to exist") # Useful when you run your Python script from the terminal and you want to hold the running to see your figures until you press Enter

16
Làm thế nào một nhấn nhấn trước khi tồn tại?
grovina

2

OP hỏi về việc tháo gỡ matplotlibcác lô. Hầu hết các câu trả lời giả định thực thi lệnh từ bên trong một trình thông dịch python. Ca sử dụng được trình bày ở đây là ưu tiên của tôi để kiểm tra mã trong một thiết bị đầu cuối (ví dụ bash) trong đó a file.pyđược chạy và bạn muốn (các) cốt truyện xuất hiện nhưng tập lệnh python hoàn thành và quay lại dấu nhắc lệnh.

Tệp độc lập này sử dụng multiprocessingđể khởi chạy một quy trình riêng để vẽ dữ liệu matplotlib. Các chủ đề chính thoát ra bằng cách sử dụng os._exit(1)đề cập trong bài viết này . Các os._exit()lực lượng chính để thoát nhưng để matplotlibquá trình con sống và đáp ứng cho đến khi cửa sổ cốt truyện được đóng lại. Đó là một quá trình riêng biệt hoàn toàn.

Cách tiếp cận này hơi giống với phiên phát triển Matlab với các cửa sổ hình xuất hiện với dấu nhắc lệnh phản hồi. Với phương pháp này, bạn đã mất tất cả liên lạc với quy trình cửa sổ hình, nhưng, điều đó ổn cho việc phát triển và gỡ lỗi. Chỉ cần đóng cửa sổ và tiếp tục thử nghiệm.

multiprocessingđược thiết kế để thực thi mã chỉ python khiến nó có lẽ phù hợp hơn subprocess. multiprocessinglà đa nền tảng nên điều này sẽ hoạt động tốt trong Windows hoặc Mac với ít hoặc không cần điều chỉnh. Không cần phải kiểm tra hệ điều hành cơ bản. Điều này đã được thử nghiệm trên linux, Ubuntu 18.04LTS.

#!/usr/bin/python3

import time
import multiprocessing
import os

def plot_graph(data):
    from matplotlib.pyplot import plot, draw, show
    print("entered plot_graph()")
    plot(data)
    show() # this will block and remain a viable process as long as the figure window is open
    print("exiting plot_graph() process")

if __name__ == "__main__":
    print("starting __main__")
    multiprocessing.Process(target=plot_graph, args=([1, 2, 3],)).start()
    time.sleep(5)
    print("exiting main")
    os._exit(0) # this exits immediately with no cleanup or buffer flushing

Chạy file.pysẽ xuất hiện một cửa sổ hình, sau đó __main__thoát nhưng cửa sổ multiprocessing+ matplotlibhình vẫn phản hồi với các nút thu phóng, xoay và các nút khác vì đây là một quá trình độc lập.

Kiểm tra các quy trình tại dấu nhắc lệnh bash với:

ps ax|grep -v grep |grep file.py


Tôi đã cố gắng sử dụng giải pháp của bạn nhưng dường như nó không hiệu quả với tôi và tôi đang cố gắng tìm hiểu tại sao. Tôi không chạy mã thông qua thiết bị đầu cuối mà từ IDE Pycharm nếu điều đó tạo ra sự khác biệt, mặc dù không nên.
ttsesm

1
ok, điều cuối cùng làm việc cho tôi là thiết lập quy trình con với .daemon=Falsenhư được mô tả ở đây stackoverflow.com/a/49607287/1476932 Tuy nhiên, sys.exit()đã không chấm dứt quy trình cha mẹ như được mô tả ở đó cho đến khi tôi đóng cửa sổ con. Mặt khác, sử dụng os._exit(0)từ ví dụ trên đã làm việc.
ttsesm


0

Nếu bạn muốn mở nhiều số liệu, trong khi vẫn giữ tất cả chúng được mở, mã này hoạt động với tôi:

show(block=False)
draw()

chương trình (khối = Sai) đã bị phản đối và hiện không hoạt động nữa
Bogdan

0

Mặc dù không trả lời trực tiếp yêu cầu của OP, tôi đăng bài giải pháp này vì nó có thể giúp ai đó trong tình huống này:

  • Tôi đang tạo một .exe với pyinstaller vì tôi không thể cài đặt python nơi tôi cần tạo các ô, vì vậy tôi cần tập lệnh python để tạo cốt truyện, lưu nó dưới dạng .png, đóng nó và tiếp tục với phần tiếp theo, được triển khai như một số lô trong một vòng lặp hoặc sử dụng một chức năng.

cho việc này tôi đang sử dụng:

import matplotlib.pyplot as plt
#code generating the plot in a loop or function
#saving the plot
plt.savefig(var+'_plot.png',bbox_inches='tight', dpi=250) 
#you can allways reopen the plot using
os.system(var+'_plot.png') # unfortunately .png allows no interaction.
#the following avoids plot blocking the execution while in non-interactive mode
plt.show(block=False) 
#and the following closes the plot while next iteration will generate new instance.
plt.close() 

Trong đó "var" xác định cốt truyện trong vòng lặp để nó không bị ghi đè.


-1

Sử dụng plt.show(block=False), và vào cuối cuộc gọi kịch bản của bạn plt.show().

Điều này sẽ đảm bảo rằng cửa sổ sẽ không bị đóng khi tập lệnh kết thúc.


Xem câu trả lời của @ nico-schlömer
Josh Wolff
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.