wxPython: Draw animation and graph drawing at the same time

[Deep Q Learning with Chainer --Launch-- Qiita](http://qiita.com/chachay/items/5fdb7c64af68bcacf7d3#wxpython%E3%81%AE%E4%BD%BF%E3%81%84 I didn't understand with% E6% 96% B9)

I want to add a graph at the bottom of the screen

It is a supplementary lesson. 002.gif

environment

Preparation

The Windows installer version of wx.lib.plot has a bug in plot.py and cannot plot. Rewrite C: \ Python27 \ Lib \ site-packages \ wx-3.0-msw \ wx \ lib \ plot.py.

The rewrite source is the latest version of Github ⇒ here wxPython / plot.py at master · wxWidgets / wxPython

reference: Crash on pyplot demo - Google Groups

import

No particular ingenuity

python


import wx
import wx.lib
import wx.lib.plot as plot

Preparing the window frame

Suddenly I come to the conclusion, Frame->Panel -> BoxSizer-> Plot (animation) -> PlotCanvas Just define the panel and so on with the hanging structure and plot the animation and graph.

python


class MyWindow(wx.Frame):
    def __init__(self, parent=None, id=-1, title=None):
        wx.Frame.__init__(self, parent, id, title)

        self.MainPanel = wx.Panel(self, size=(640, 480))
        
        self.panel = wx.Panel(self.MainPanel, size=(300, 480))
        self.panel.SetBackgroundColour('WHITE')
        
        self.plotter = plot.PlotCanvas(self.MainPanel, size=(340, 480))
        self.plotter.SetEnableZoom(False)
        self.plotter.SetEnableLegend(True)
        self.plotter.SetFontSizeLegend(20)
        
        self.i = 0
        self.data = []
        line = plot.PolyLine(self.data, legend='Dummy', colour='pink', width=2)
        self.gc = plot.PlotGraphics([line], 'Line Graph', 'X Axis', 'Y Axis')
        self.plotter.Draw(self.gc, xAxis=(0,15), yAxis=(0,15))      
        self.plotter.SetFontSizeLegend(point=10.5)
        
        mainSizer = wx.BoxSizer(wx.HORIZONTAL)
        mainSizer.Add(self.panel)
        mainSizer.Add(self.plotter)
        
        self.SetSizer(mainSizer)

        self.Fit()

Graph update while animating

I am animating with OnTimer, but I just add a graph update at the end

python


        self.data.append((self.i, groundH - self.ball.pos_y))
        if len(self.data) >= 100:
            self.data = self.data[-101:]

        line = plot.PolyLine(self.data, legend='Pos Y', colour='red', width = 1)
        self.gc = plot.PlotGraphics([line], 'Line Graph', 'X Axis', 'Y Axis')
        self.plotter.Draw(self.gc, xAxis=(max(0,self.i-100), self.i), yAxis=(0, groundH))
        self.i += 1

All code

python


# -*- coding: utf-8 -*-
import wx
import wx.lib
import wx.lib.plot as plot

import math

dT = 20
g  = 640.0
groundH = 410

class Ball(object):
    def __init__(self, panel, x, y, color):
        self.pos_x = float(x)
        self.pos_y = float(y)
        
        self.vx = 0.0
        self.vy = 0.0
        
        self.rad = 10.0
                
        self.pos_x_max, self.pos_y_max = panel.GetSize()
        self.B_color = color
        self.P_color = wx.Colour(50,50,50)
 
    def Move(self, ax = 0.0, ay = 0.0):
        self.vx += ax * dT / 1000.0
        self.vy += ay * dT / 1000.0
    
        self.pos_x += self.vx * dT / 1000.0
        self.pos_y += self.vy * dT / 1000.0
    
        self.pos_x = max(0, min(self.pos_x, self.pos_x_max))
        self.pos_y = max(0, min(self.pos_y, groundH))
 
    def Draw(self, dc):
        dc.SetPen(wx.Pen(self.P_color))
        dc.SetBrush(wx.Brush(self.B_color))
        dc.DrawCircle(self.pos_x, self.pos_y, self.rad)
        
    def IntersectBall(self, p0, v0):
        o = [-self.pos_x + p0[0], -self.pos_y + p0[1]]
                
        a = v0[0] ** 2 + v0[1] **2
        b = 2 * (o[0]*v0[0]+o[1]*v0[1])
        c = o[0] ** 2 + o[1] **2 - self.rad ** 2
        
        discriminant = float(b * b - 4 * a * c)
        
        if discriminant < 0:
            return [False, 1.0]
        
        discriminant = discriminant ** 0.5
        
        t1 = (- b - discriminant)/(2*a)
        t2 = (- b + discriminant)/(2*a)
        
        if t1 >= 0 and t1 <= 1.0:
            return [True, t1]

        if t2 >= 0 and t2 <= 1.0:
            return [True, t2]

        return [False, 1.0]         

class Walls(object):
    def __init__(self, x0, y0, x1, y1):
        self.xList = [x0, x1]
        self.yList = [y0, y1]
        self.P_color = wx.Colour(50,50,50)

    def addPoint(self, x, y):
        self.xList.append(x)
        self.yList.append(y)

    def Draw(self,dc):
        dc.SetPen(wx.Pen(self.P_color))
        for i in range(0, len(self.xList)-1):
            dc.DrawLine(self.xList[i], self.yList[i], self.xList[i+1],self.yList[i+1])

class MyWindow(wx.Frame):
    def __init__(self, parent=None, id=-1, title=None):
        wx.Frame.__init__(self, parent, id, title)

        self.MainPanel = wx.Panel(self, size=(640, 480))
        
        self.panel = wx.Panel(self.MainPanel, size=(300, 480))
        self.panel.SetBackgroundColour('WHITE')
        
        self.plotter = plot.PlotCanvas(self.MainPanel, size=(340, 480))
        self.plotter.SetEnableZoom(False)
        self.plotter.SetEnableLegend(True)
        self.plotter.SetFontSizeLegend(20)
        
        self.i = 0
        self.data = []
        line = plot.PolyLine(self.data, legend='Dummy', colour='pink', width=2)
        self.gc = plot.PlotGraphics([line], 'Line Graph', 'X Axis', 'Y Axis')
        self.plotter.Draw(self.gc, xAxis=(0,15), yAxis=(0,15))      
        self.plotter.SetFontSizeLegend(point=10.5)
        
        mainSizer = wx.BoxSizer(wx.HORIZONTAL)
        mainSizer.Add(self.panel)
        mainSizer.Add(self.plotter)
        
        self.SetSizer(mainSizer)

        self.Fit()
        
        self.ball = Ball(self.panel, 150, 100, wx.Colour(237,125,49))
        
        # OutrBox
        self.Box = Walls(299, 479, 0, 479)
        self.Box.addPoint(1,1)
        self.Box.addPoint(299,1)
        self.Box.addPoint(299,480)
        
        # Ground
        self.Ground = Walls(0, 420, 300, 420)
        self.HitGround = False
 
        self.Bind(wx.EVT_CLOSE, self.CloseWindow)
 
        self.cdc = wx.ClientDC(self.panel)
        w, h = self.panel.GetSize()
        self.bmp = wx.EmptyBitmap(w,h)
 
        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.OnTimer)
        self.timer.Start(dT)
 
    def CloseWindow(self, event):
        self.timer.Stop()
        wx.Exit()
 
    def OnTimer(self, event):
        self.bdc = wx.BufferedDC(self.cdc, self.bmp)
        self.gcdc = wx.GCDC(self.bdc)

        self.gcdc.Clear()
 
        if self.HitGround and self.ball.vy > 0.1:
            self.ball.vy *= -0.8
        
        if (0.5*self.ball.vy **2 + g * (groundH - self.ball.pos_y)) < g *(groundH - 408) \
            and (groundH - self.ball.pos_y) < 2.0:
            ay = - ((groundH * g * 2.0 * 0.8) ** 0.5 / dT * 1000)
        else:
            ay = g
        
        self.ball.Move(ay = ay)
        self.HitGround,_ = self.ball.IntersectBall([0,420], [300, 0])        

        self.gcdc.SetPen(wx.Pen('white'))
        self.gcdc.SetBrush(wx.Brush('white'))
        self.gcdc.DrawRectangle(0,0,300,480)

        self.ball.Draw(self.gcdc)
        self.Box.Draw(self.gcdc)
        self.Ground.Draw(self.gcdc)
        
        self.data.append((self.i, groundH - self.ball.pos_y))
        if len(self.data) >= 100:
            self.data = self.data[-101:]

        line = plot.PolyLine(self.data, legend='Pos Y', colour='red', width = 1)
        self.gc = plot.PlotGraphics([line], 'Line Graph', 'X Axis', 'Y Axis')
        self.plotter.Draw(self.gc, xAxis=(max(0,self.i-100), self.i), yAxis=(0, groundH))
        self.i += 1

 
if __name__ == '__main__':
    app = wx.PySimpleApp()
    w = MyWindow(title='Bounce Ball')
    w.Center()
    w.Show()
    app.MainLoop()

Recommended Posts

wxPython: Draw animation and graph drawing at the same time
Visualize data and understand correlation at the same time
Browse .loc and .iloc at the same time in pandas DataFrame
Behind the graph drawing algorithm and Networkx
Plot multiple maps and data at the same time with Python's matplotlib
Loop variables at the same time in the template
I want to make a music player and file music at the same time
I tried the same data analysis with kaggle notebook (python) and Power BI at the same time ②
Steps to change table and column names in your Django model at the same time
I tried the same data analysis with kaggle notebook (python) and Power BI at the same time ①
Python built-in function ~ divmod ~ Let's get the quotient and remainder of division at the same time
python memo: enumerate () -get index and element of list at the same time and turn for statement
[Python 3.8 ~] Rewrite arrays etc. at the same time as definition [tips]
Technique to stop drawing the screen and reduce the waiting time for baking
Set up a server that processes multiple connections at the same time
[Python] How to open two or more files at the same time
Call the python debugger at any time
Draw a graph with PyQtGraph Part 1-Drawing
Python open and io.open are the same
Make sure to align the pre-processing at the time of forecast model creation and forecast
Type conversion of multiple columns of pandas DataFrame with astype at the same time
Turn multiple lists with a for statement at the same time in Python