График неправильно обновляется с помощью draw() (дублированные оси) в wxPython

Я новичок в Python и wxPython. Я пытаюсь смоделировать частицы в коробке со случайными скоростями в случайных направлениях. Я создал простой графический интерфейс в wxFormBuilder, где у меня есть панель для отображения графика частиц. Частицы устанавливаются в положение и отображаются на панели, затем я запускаю симуляцию и обновляю координаты частиц по осям x и y. При перерисовке позиций оси кажутся «толще», как и раньше, похоже, что несколько осей расположены друг над другом.

Я ничего не могу найти об этой проблеме, я надеюсь, что кто-нибудь может мне помочь с этим?

Это код, который создает Plot:

import wx
import particles


import random
import matplotlib
matplotlib.use('WXAgg')
from matplotlib.figure import Figure
from matplotlib.backends.backend_wxagg import \
        FigureCanvasWxAgg as FigCanvas, \
        NavigationToolbar2WxAgg as NavigationToolbar
matplotlib.rcParams.update({'font.size': 8})

class MyFrameSub( particles.GUI_MainFrame ):
    def __init__( self, parent ):
        particles.GUI_MainFrame.__init__( self, parent )

    def InitData(self):
        self.npart = int(self.m_npart.GetValue())
        self.nsteps = int(self.m_steps.GetValue())
        self.ndt = float(self.m_dt.GetValue())

        self.x= [random.random() for I in range(self.npart)]
        self.y= [2*random.random()-1 for I in range(self.npart)]
        self.vx= [self.ndt*(2*random.random()-1) for I in range(self.npart)]
        self.vy= [self.ndt*(2*random.random()-1) for I in range(self.npart)]
        return

    def CreatePlot(self):
        panelsize = self.m_PlotPanel.GetClientSize()
        self.figure = Figure(figsize=(panelsize[0]/100.0,panelsize[1]/100.0), dpi=100, frameon=False)

        self.canvas = FigCanvas(self.m_PlotPanel, wx.ID_ANY, self.figure)

        self.axes = self.figure.add_subplot(111)
        self.axes.axis((-1,1,-1,1))

        self.partplot, = self.axes.plot(self.x, self.y, 'ro')

        self.canvas.draw()
        return

    def UpdateData(self):
        for i in range(self.nsteps):
            for j in range(self.npart):
                self.x[j]=self.x[j]+self.vx[j]
                self.y[j]=self.y[j]+self.vy[j]

                if abs(self.x[j])>1:
                    self.vx[j]=-self.vx[j]
                if abs(self.y[j])>1:
                    self.vy[j]=-self.vy[j]

            self.partplot.set_xdata(self.x)
            self.partplot.set_ydata(self.y)
            self.canvas.draw()
        return

за которыми следуют определения кнопок, это выглядит так: Перед запуском моделирования: www.merlinvs.de/before. jpg

введите здесь описание изображения

и после запуска моделирования: www.merlinvs.de/after.jpg

введите здесь описание изображения

Как видите, топоры стали уродливыми, и я понятия не имею, почему.

Еще один вопрос, о котором я думал, заключается в следующем: когда я запускаю цикл, который занимает некоторое время, пользовательский интерфейс не отвечает, возможно ли активировать пользовательский интерфейс для отмены цикла, если это необходимо?


person Merlin    schedule 25.04.2012    source источник
comment
Решение упомянутой выше проблемы описано на следующих страницах: Link1 Link2 особенно вторая ссылка содержит подробную информацию. Я не знаю, как закрыть этот вопрос, так как мне не разрешено принимать ответ, который я написал сам.   -  person Merlin    schedule 26.04.2012


Ответы (1)


Что касается неотзывчивого пользовательского интерфейса, я использовал зеленые элементы для своего материала Matplotlib при его обновлении.

from gevent.greenlet import Greenlet
from gevent import sleep
import matplotlib.plot as plt

# Plot stuff

def event_handler():
  # Can update plot
  sleep(1) # Simulate handling or number crunching (numpy WILL block)

g = Greenlet(event_handler)
g.start()
plt.plot(0,0) # Works immediately and updates

Следует отметить, что для серьезных приложений вам необходимо добавить некоторую защиту от гонок с сюжетом. Numpy и внешние научные библиотеки обычно приводят к тому, что все приложение перестает отвечать на запросы (по моему опыту), потому что они блокируют системные вызовы за пределами досягаемости переключателя контекста greenlet. Для чего-то простого, хотя приведенный выше шаблон работает хорошо.

person lukecampbell    schedule 25.04.2012
comment
Спасибо, что указали на гринлеты, это выглядит очень интересно. Я прочитаю об этом, так как я еще не все понимаю. - person Merlin; 26.04.2012
comment
Greenlets — это нитевидные тасклеты, которые упорядочиваются и переключаются в экземпляре Python. Из-за глобальной блокировки интерпретатора Python потоки неэффективны, поэтому Greenlets вмешиваются и контролируют переключение контекста и предоставляют очень чистый API для использования параллелизма, в данном случае один для вашего графика и один для вашего цикла событий (прослушивание действий пользователя). - person lukecampbell; 26.04.2012