هل هناك طريقة لفصل مخططات matplotlib بحيث يمكن مواصلة الحساب؟

StackOverflow https://stackoverflow.com/questions/458209

  •  19-08-2019
  •  | 
  •  

سؤال

بعد هذه التعليمات في مترجم بايثون، يحصل المرء على نافذة تحتوي على قطعة أرض:

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

لسوء الحظ، لا أعرف كيفية الاستمرار في استكشاف الشكل الذي أنشأه بشكل تفاعلي show() بينما يقوم البرنامج بإجراء المزيد من العمليات الحسابية.

هل هذا من الممكن بأبة طريقة؟في بعض الأحيان تكون الحسابات طويلة وسيكون من المفيد الاستمرار فيها أثناء فحص النتائج المتوسطة.

هل كانت مفيدة؟

المحلول

استخدم المكالمات matplotlib التي لن تمنع:

وعن طريق 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()
<ع> استخدام طريقة تفاعلية:

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

نصائح أخرى

استخدم الكلمة الأساسية 'كتلة "لتجاوز السلوك حظر، على سبيل المثال،

from matplotlib.pyplot import show, plot

plot(1)  
show(block=False)

# your code

للمتابعة التعليمات البرمجية.

من الأفضل دائمًا التحقق من المكتبة التي تستخدمها إذا كانت تدعم الاستخدام في ملف غير مانع طريق.

ولكن إذا كنت تريد حلاً أكثر عمومية، أو إذا لم تكن هناك طريقة أخرى، فيمكنك تشغيل أي شيء يحظر في عملية منفصلة باستخدام multprocessing الوحدة المضمنة في بيثون.سيستمر الحساب:

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

ينطوي ذلك على عبء إطلاق عملية جديدة، وفي بعض الأحيان يصعب تصحيح الأخطاء في السيناريوهات المعقدة، لذلك أفضل الحل الآخر (باستخدام matplotlibمكالمات API غير المحظورة)

وحاول

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

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

الوثائق show() يقول:

<اقتباس فقرة>   

في الوضع غير التبادلي، وعرض كل الأرقام وكتلة حتى يتم إغلاق الأرقام. في الوضع التفاعلي يكون له أي تأثير إلا إذا تم إنشاؤها الأرقام قبل تغيير من غير التبادلي إلى الوضع التفاعلي (غير مستحسن). في هذه الحالة فإنه يعرض الأرقام ولكن لا يمنع.

     

وهناك حجة الكلمة تجريبية واحدة، block، قد يتم تعيين لTrue أو False لتجاوز السلوك الحجب هو موضح أعلاه.

قد ترغب في قراءة هذه الوثيقة في matplotlibتوثيق بعنوان :

باستخدام matplotlib في قذيفة بيثون

مهم:فقط لتوضيح شيء ما.أفترض أن الأوامر موجودة داخل ملف .py البرنامج النصي ويتم استدعاء البرنامج النصي باستخدام على سبيل المثال. python script.py من وحدة التحكم.

الطريقة البسيطة التي تناسبني هي:

  1. استخدم الكتلة = خطأ داخل العرض: plt.show(كتلة = خطأ)
  2. يستخدم آخر يعرض() .في نهايةالمطاف من البرنامج النصي .py.

مثال على script.py ملف:

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

في حالتي، كنت أريد أن يكون عدة نوافذ يطفو على السطح كما يتم حسابها. للإشارة، هذه هي الطريقة:

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

وPS. A توجيه إلى matplotlib واجهة OO .

حسنا، كان لدي صعوبة كبيرة في معرفة الأوامر غير مؤمن ... ولكن في النهاية، تمكنت من إعادة صياغة "<لأ href =" http://www.scipy.org/Cookbook/Matplotlib/Animations#head -3d51654b8306b1585664e7fe060a60fc76e5aa08 "يختلط =" noreferrer "> كتاب الطبخ / Matplotlib / الرسوم المتحركة - موحية تحديد عناصر المؤامرة " مثلا، لذلك يعمل مع الخيوط (<م> ويمر البيانات بين المواضيع إما عن طريق المتغيرات العالمية، أو من خلال Pipe multiprocess ) على بايثون 2.6.5 على أوبونتو 10.04.

والسيناريو يمكن العثور عليها هنا: <لأ href = "http://sdaaubckp.svn.sourceforge.net/viewvc/sdaaubckp/single-scripts/Animating_selected_plot_elements-thread.py؟revision=101&content-type=text٪2Fplain "يختلط =" noreferrer "> Animating_selected_plot_elements-thread.py - لصق إلا أقل من (<م> مع عدد أقل من تعليقات ) للرجوع اليها:

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! 

وآمل أن يساعد هذا شخص ما،
هتاف!

في كثير من الحالات هو عليه أكثر ملاءمة حتى حفظ الصورة كملف .png على القرص الصلب.هنا هو السبب:

مزايا:

  • يمكنك فتحه وإلقاء نظرة عليه وإغلاقه في أي وقت أثناء العملية.هذا مريح بشكل خاص عندما يعمل تطبيقك لفترة طويلة.
  • لا شيء ينبثق ولا تضطر إلى فتح النوافذ.وهذا مناسب بشكل خاص عندما تتعامل مع العديد من الشخصيات.
  • يمكن الوصول إلى صورتك للرجوع إليها لاحقًا ولا تضيع عند إغلاق نافذة الشكل.

عائق:

  • الشيء الوحيد الذي يمكنني التفكير فيه هو أنه سيتعين عليك البحث عن المجلد وفتح الصورة بنفسك.

إذا كنت تعمل في وحدة التحكم، أي IPython هل يمكن استخدام plt.show(block=False) كما أشار في إجابات أخرى. ولكن إذا كنت كسول يمكنك كتابة فقط:

plt.show(0)

والتي سوف تكون هي نفسها.

وكان لي أيضا أن أضيف plt.pause(0.001) إلى رمز جهدي لجعل حقا انها تعمل داخل لحلقة (وإلا فإنه سوف تظهر فقط المؤامرة الأولى والأخيرة):

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 مشفرة يصل هذا الإختراق قليلا بحيث أن أي مؤامرات داخل بيان with هذا تتصرف على هذا النحو.

وهذا هو على الارجح قليلا جدا غير قياسي وغير المستحسن لرمز الإنتاج. وربما هناك الكثير من "gotchas" مخبأة في هذا القانون.

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 اضغط ص إذا كنت تريد إخراج بالتخطيط ليكون مؤقتا (لديك 5 ثوان):" من <لأ href = "HTTPS: // ستاكوفيرفلوو كوم / الأسئلة / 26704840 / الزاوية الحالات مقابل بلدي الانتظار مقابل المستخدم المدخلات وتوقف التنفيذ "> https://stackoverflow.com/questions/26704840/corner-cases-for-my-wait- مقابل المستخدم المدخلات وتوقف التنفيذ .

في برنامجي النظام () لا يمنع، على الرغم من أنني أرغب في السيناريو الانتظار للمستخدم التفاعل مع الرسم البياني (وجمع البيانات باستخدام الاسترجاعات "pick_event ') قبل المتابعة.

في أجل منع تنفيذ حتى يتم إغلاق نافذة المؤامرة، واعتدت ما يلي:

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

ملحوظة، مع ذلك، أن canvas.start_event_loop_default () ينتج التحذير التالي:

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)

وعلى الرغم من أن السيناريو لا يزال يدير.

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

في رأيي، والأجوبة في هذا الموضوع توفر الأساليب التي لا تعمل من أجل كل النظم وفي حالات أكثر تعقيدا مثل الرسوم المتحركة. أقترح أن نلقي نظرة على إجابة لMiKTeX في الموضوع التالي، حيث تم العثور على وسيلة قوية: كيفية الانتظار حتى ينتهي matplotlib الرسوم المتحركة؟

إذا كنت ترغب في فتح شخصيات متعددة، مع إبقائها فتح كل شيء، عملت هذا الرمز بالنسبة لي:

show(block=False)
draw()

ووOP يسأل عن detatching المؤامرات matplotlib. تفترض معظم الإجابات تنفيذ الأمر من خلال مترجم الثعبان. وحدة استخدام المعروضة هنا هي تفضيل بلدي لرمز اختبار في محطة (على سبيل المثال باش) حيث يتم تشغيل file.py وتريد مؤامرة (ق) من أجل التوصل إلى ولكن السيناريو الثعبان لاستكمال والعودة إلى موجه الأوامر.

وهذا ملف مستقل يستخدم multiprocessing لإطلاق عملية منفصلة بتهمة التآمر مع البيانات matplotlib. مخارج موضوع الرئيسية باستخدام os._exit(1) المذكورة في هذا آخر . قوات os._exit() الرئيسية للخروج ولكنه يترك عملية طفل matplotlib على قيد الحياة واستجابة حتى يتم إغلاق نافذة المؤامرة. انها عملية منفصلة تماما.

وهذا النهج هو قليلا مثل جلسة تطوير ماتلاب مع نوافذ شخصية التي تأتي مع موجه الأوامر استجابة. مع هذا النهج، كنت قد فقدت كل اتصال مع عملية نافذة الشكل، ولكن، وهذا موافق لتطوير وتصحيح الأخطاء. مجرد إغلاق نافذة والحفاظ على الاختبار.

تم تصميم multiprocessing لتنفيذ الثعبان فقط كود مما يجعله ربما يكون أكثر ملاءمة من subprocess. multiprocessing هو عبر منصة هذا ما ينبغي أن تعمل بشكل جيد في ويندوز أو ماكنتوش مع تعديل ضئيلة أو معدومة. ليست هناك حاجة للتحقق من نظام التشغيل الأساسي. تم اختبار هذا على لينكس، أوبونتو 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

وتشغيل file.py إحضار نافذة الرقم، ثم __main__ مخارج لكن يبقى نافذة multiprocessing + الرقم matplotlib استجابة مع التكبير، والقومية، والأزرار الأخرى لأنها عملية مستقلة.

والتحقق من العمليات في موجه الأوامر باش مع:

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

استخدم plt.show(block=False)، وفي نهاية الخاص بك plt.show() دعوة النصي.

وهذا سيضمن أن الإطار لن تكون مغلقة عند الانتهاء من البرنامج النصي.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top