أردت رسم بياني لبعض البيانات التي كنت أقوم بإنشائها من تطبيق اقتراع بسيط. لقد قمت بالتعديل على pyplot في الماضي، لكنني لم أحاول إنشاء أي شيء من الصفر. ولحسن الحظ، فهو يحظى بشعبية كبيرة، وهناك الكثير من الأمثلة التي يمكن العثور عليها في StackOverflow وأماكن أخرى.
لقد أجريت بحثًا وبدأت بإجابة SO هذه المتعلقة بتحديث الرسم البياني بمرور الوقت.
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()
يعمل هذا الكود على تنشيط مرحلة تغيير الموجة الجيبية.
يستورد السطران الأولان المكتبات التي أرغب في استخدامها: يقوم matplotlib.pyplot بتخطيط واجهة المستخدم الرسومية والتعامل معها.
إن طريقة ion()، إذا فهمت (على الرغم من أنني قد لا أفهم ذلك)، تجعل pyplot يقود واجهة المستخدم الرسومية. يمكنك أيضًا استخدامه داخل برنامج tkinter، أو استخدامه لإنشاء صور ثابتة، ولكن في حالتنا فمن المنطقي السماح له بالتعامل مع واجهة المستخدم الرسومية الخاصة بالمؤامرة بالنسبة لنا. (وهذا ما يفعله الدالة Flush_events() لاحقًا: السماح بالتفاعل مع نافذة الشكل.)
يستخدم هذا المثال الطريقة numpy linspace() لإنشاء قيم x. تقوم بإرجاع مصفوفة numpy، وهي قائمة بايثون رائعة.
سبب استخدام np.sin بدلاً من math.sin هو البث. هذا هو المصطلح numpy لتطبيق الوظيفة على كل عنصر في القائمة. في الواقع، يخطر لي أنه يمكن تحقيق نفس الشيء بدون استخدام numpy الخريطة:
map(lambda n: math.sin(n), x)
لكن البث numpy مريح وسهل الاستخدام.
الآن يأتي إعداد pyplot. أولاً، قم بإنشاء "شكل" جديد (الشكل). في هذا الشكل، أضف حبكة فرعية (فأس) - يمكن أن يكون هناك الكثير. 111 له تفسير مقصور على فئة معينة، "قم بإنشاء شبكة 1 × 1، ثم ضع هذه الحبكة الفرعية في الخلية الأولى."
في هذه الحبكة الفرعية (أو مجموعة المحاور)، يتم رسم خط باستخدام قيم x وy التي تم تمريرها. (ترتبط النقاط بخطوط مستقيمة ويتم رسمها بشكل مستمر.) "r-" هي الطريقة المختصرة لتحديد خط أحمر متصل. يمكننا تحديد عدة أسطر، لذا تُرجع مؤامرة () صفًا؛ يستخدم الكود أعلاه تفريغ الصف لاستخراج القيمة الوحيدة التي نريدها.
إنها بداية جيدة، لكني بحاجة إلى تمديد المحور السيني بمرور الوقت. لا يقوم هذا الرمز أيضًا بتحديث حدود المحور y إذا لزم الأمر - فهو مقيد بأي حدود يحسبها للمخطط الأول. المزيد من البحث يقودني إلى إجابة SO هذه. على حد تعبيرهم:
ستحتاج إلى تحديث dataLim للمحاور، ثم تحديث viewLim للمحاور بناءً على dataLim. الطرق المناسبة هي طريقة axes.relim() و ax.autoscale_view().
بالتأكيد، يبدو جيدًا. واستنادًا إلى مثالهم، قمت بإنشاء رسم بياني تجريبي ينمو في كل من x و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)
الآن سأصل إلى مكان ما. ولكن هذه حلقة حظر، وأحتاج إلى تحديث بياناتي من حين لآخر. إذا كان لدي عدة سلاسل رسائل، فيجب أن أقلق بشأن كون سلاسل الرسائل آمنة عند تحديث المتغيرات الخاصة بي. في هذه الحالة، يمكن أن أكون كسولًا لأنني أعلم أن المتغير يتم تحديثه مرة واحدة فقط كل 5 دقائق (أو في كثير من الأحيان يتم تشغيل وظيفة الاستقصاء)؛ ليس هناك خطر من الكتابة فوق المتغير في منتصف سطر من التعليمات البرمجية.
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)
يتم تحديث الرسم البياني فقط عندما يقوم مؤشر ترابط النمو بتعيين قيمة لـ new_x. لاحظ أن استدعاء Flush_events() يقع خارج عبارة "if"، بحيث يتم استدعاؤه بشكل متكرر.
تنصل: جميع الموارد المقدمة هي جزئيًا من الإنترنت. إذا كان هناك أي انتهاك لحقوق الطبع والنشر الخاصة بك أو الحقوق والمصالح الأخرى، فيرجى توضيح الأسباب التفصيلية وتقديم دليل على حقوق الطبع والنشر أو الحقوق والمصالح ثم إرسالها إلى البريد الإلكتروني: [email protected]. سوف نتعامل مع الأمر لك في أقرب وقت ممكن.
Copyright© 2022 湘ICP备2022001581号-3