Saya ingin membuat graf beberapa data yang saya hasilkan daripada apl tinjauan pendapat mudah. Saya telah bermain-main dengan pyplot pada masa lalu, tetapi saya tidak cuba mencipta apa-apa dari awal. Nasib baik, ia benar-benar popular, dan terdapat banyak contoh yang boleh ditemui di StackOverflow dan di tempat lain.
Saya melakukan carian dan bermula dengan jawapan SO ini berkaitan dengan mengemas kini graf dari semasa ke semasa.
import matplotlib.pyplot as plt import numpy as np # You probably won't need this if you're embedding things in a tkinter plot... plt.ion() x = np.linspace(0, 6*np.pi, 100) y = np.sin(x) fig = plt.figure() ax = fig.add_subplot(111) line1, = ax.plot(x, y, 'r-') # Returns a tuple of line objects, thus the comma for phase in np.linspace(0, 10*np.pi, 500): line1.set_ydata(np.sin(x + phase)) fig.canvas.draw() fig.canvas.flush_events()
Kod ini menghidupkan fasa perubahan gelombang sinus.
Dua baris pertama mengimport perpustakaan yang saya mahu gunakan: matplotlib.pyplot melakukan perancangan dan pengendalian GUI.
Kaedah ion(), jika saya faham (walaupun mungkin tidak), menjadikan pyplot memacu GUI. Anda juga boleh menggunakannya di dalam program tkinter, atau menggunakannya untuk menjana imej statik, tetapi dalam kes kami adalah wajar untuk membiarkannya mengendalikan GUI plot untuk kami. (Itulah yang dilakukan oleh flush_events() kemudiannya: membenarkan interaktiviti dengan tetingkap angka.)
Contoh ini menggunakan kaedah numpy linspace() untuk mencipta nilai x. Ia mengembalikan tatasusunan numpy, iaitu senarai Python yang mewah.
Sebab untuk menggunakan np.sin dan bukannya math.sin adalah penyiaran. Itulah istilah numpy untuk menggunakan fungsi pada setiap item dalam senarai. Malah, saya terfikir bahawa perkara yang sama boleh dicapai tanpa numpy menggunakan peta:
map(lambda n: math.sin(n), x)
Tetapi penyiaran numpy adalah mudah dan mudah untuk digunakan.
Kini datang persediaan pyplot. Mula-mula, buat "angka" baharu (rajah). Dalam angka ini, tambahkan subplot (kapak) -- mungkin terdapat banyak. 111 mempunyai tafsiran yang agak esoterik, "buat grid 1x1, dan letakkan subplot ini dalam sel pertama."
Ke dalam subplot ini (atau set paksi), garis diplot menggunakan nilai x dan y yang diluluskan. (Titik disambungkan dengan garis lurus dan diplot secara berterusan.) "r-" ialah cara singkat untuk menentukan garis merah pepejal. Kita boleh menentukan berbilang baris, jadi plot() mengembalikan tuple; kod di atas menggunakan tuple unpacking untuk mengekstrak satu nilai yang kita mahu.
Ini adalah permulaan yang baik, tetapi saya perlu memanjangkan paksi-x dari semasa ke semasa. Kod ini juga tidak mengemas kini sempadan paksi-y jika perlu -- ia dikunci ke dalam sebarang sempadan yang dikira untuk plot pertama. Sedikit lagi carian membawa saya kepada jawapan SO ini. Untuk memetik mereka:
Anda perlu mengemas kini dataLim paksi, kemudian mengemas kini viewLim paksi berdasarkan dataLim. Kaedah yang sesuai ialah kaedah axes.relim() dan ax.autoscale_view().
Sudah tentu, bunyinya bagus. Berdasarkan contoh mereka, saya mencipta graf demo yang tumbuh dalam kedua-dua x dan y.
import matplotlib.pyplot as plt import numpy as np from threading import Thread from time import sleep x = list(map(lambda x: x / 10, range(-100, 100))) x_next_max = 100 y = np.sin(x) # You probably won't need this if you're embedding things in a tkinter plot... plt.ion() fig = plt.figure() ax = fig.add_subplot(111) line1 = ax.plot(x, y, 'r-')[0] # Returns a tuple of line objects growth = 0 while True: x.append(x_next_max / 10) x_next_max += 1 line1.set_xdata(x) line1.set_ydata(np.sin(x) + np.sin(np.divide(x, 100)) + np.divide(x, 100)) ax.relim() ax.autoscale() fig.canvas.draw() fig.canvas.flush_events() sleep(0.1)
Sekarang saya sampai ke suatu tempat. Tetapi, ini adalah gelung menyekat, dan saya memerlukan data saya dikemas kini sekali-sekala. Jika saya mempunyai berbilang utas, saya perlu bimbang tentang keselamatan benang dengan mengemas kini pembolehubah saya. Dalam kes ini, saya boleh menjadi malas kerana saya tahu bahawa pembolehubah hanya dikemas kini sekali setiap 5 minit (atau bagaimanapun selalunya fungsi pengundian berjalan); tiada bahaya pembolehubah ditimpa di tengah baris kod.
import matplotlib.pyplot as plt import numpy as np from threading import Timer from time import sleep x = list(map(lambda x: x / 10, range(-100, 100))) x_next_max = 100 y = np.sin(x) # You probably won't need this if you're embedding things in a tkinter plot... plt.ion() fig = plt.figure() ax = fig.add_subplot(111) line1 = ax.plot(x, y, 'r-')[0] # Plot returns a tuple of line objects growth = 0 new_x = None dT = 1 def grow(): global new_x, x_next_max while True: new_x = x + [x_next_max / 10] x_next_max += 1 sleep(dT) # grow every dT seconds t = Thread(target=grow) t.start() while True: if new_x: x = new_x new_x = None line1.set_xdata(x) line1.set_ydata(np.sin(x) + np.sin(np.divide(x, 100)) + np.divide(x, 100)) ax.relim() ax.autoscale() fig.canvas.draw() fig.canvas.flush_events() sleep(0.1)
Graf hanya dikemas kini apabila urutan tumbuh memberikan nilai kepada new_x. Perhatikan bahawa panggilan flush_events() berada di luar pernyataan "if", supaya panggilan itu kerap dipanggil.
Atas ialah kandungan terperinci Memplot masa nyata dengan pyplot. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!