HOME/Articles/

matplotlib example GForcePlotUsingPySimpleGUI (snippet)

Article Outline

Python matplotlib example 'GForcePlotUsingPySimpleGUI'

Functions in program:

  • def main():

Modules used in program:

  • import matplotlib.gridspec as gridspec
  • import matplotlib.animation as animation
  • import matplotlib.pyplot as plt
  • import random, math
  • import tkinter as tk
  • import matplotlib.backends.tkagg as tkagg
  • import PySimpleGUI as sg
  • import sys

python GForcePlotUsingPySimpleGUI

Python matplotlib example: GForcePlotUsingPySimpleGUI

#!/usr/bin/env python
import sys
if sys.version_info[0] >= 3:
    import PySimpleGUI as sg
else:
    import PySimpleGUI27 as sg

from random import randint
import PySimpleGUI as sg
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, FigureCanvasAgg
from matplotlib.figure import Figure
import matplotlib.backends.tkagg as tkagg
import tkinter as tk

import random, math
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import matplotlib.gridspec as gridspec

class MakeFig:

    def __init__(self):
        self.numOfPoints = 1  # How many current G-force points do we want?
        self.theta = .4  # controls resolution of outer bound points, smaller theta = more points

        # random starter values for global stuff
        self.ActTheta = 0.0
        self.ActRadius = 0.0
        self.points = []
        self.outerPoints = []
        self.barlist = []
        self.maxOverallG = .1
        self.maxSectorG = .1
        self.currentMaxG = .1
        self.fig = plt.figure()
        self.gs = gridspec.GridSpec(2, 1, height_ratios=[4, 1])

        self.ax1 = self.fig.add_subplot(self.gs[0], projection='polar')
        self.ax2 = self.fig.add_subplot(self.gs[1])
        self.initBounds()
        self.initGPoints()
        self.initBars()


    def outerGridCreate(self):
        radius = .5
        p1 = (radius, 0)
        thetaWorking = 0
        while thetaWorking < 2 * math.pi:
            self.outerPoints.append(p1)
            thetaWorking = round((thetaWorking + self.theta), 6)
            p1 = (thetaWorking, radius)

        self.outerPoints.pop(0)  # remove last entry for drawing reasons.

    def randomPoint(self):
        RThet = random.randint(-9, 9) / 20
        RRad = random.randint(-9, 9) / 20
        self.ActTheta = self.ActTheta + RThet
        self.ActRadius = self.ActRadius + RRad

        if self.ActRadius < 0:
            self.ActRadius = abs(self.ActRadius)
        if self.ActRadius > 1.8:
            self.ActRadius = 0 + RRad

        if self.ActTheta < 0:
            self.ActTheta = (2 * math.pi) + self.ActTheta
        if self.ActTheta > 2 * math.pi:
            self.ActTheta = 0 + RThet

        self.ActTheta = round(self.ActTheta, 6)
        self.ActRadius = round(self.ActRadius, 6)

        self.checkOuterBounds(self.ActTheta, self.ActRadius)

        return (self.ActTheta, self.ActRadius)

    def checkOuterBounds(self, pTheta, pRad):

        DistFromCenter = pRad
        self.currentMaxG = DistFromCenter
        if self.currentMaxG == 0:
            self.currentMaxG = .1

        if DistFromCenter < .5:  # we don't need to check these points, so don't bother
            return self.maxOverallG, self.maxSectorG, self.currentMaxG

        # Use theta to figure out what sector we're in
        nearPoint1 = [p for p in self.outerPoints if (p[0] >= pTheta) and (p[0] <= (pTheta + self.theta))]
        nearPoint2 = [x for x in self.outerPoints if (x[0] < pTheta) and (x[0] > (pTheta - self.theta))]

        # If we didn't find anything, it's becuase we're at the zero line sector, so push 'em
        if nearPoint1 == []:
            nearPoint1 = [self.outerPoints[0]]
        if nearPoint2 == []:
            nearPoint2 = [self.outerPoints[-1]]

        nearPoint1 = nearPoint1[0]
        nearPoint2 = nearPoint2[0]

        # Figure out if we need to push the sector boundaries out
        if DistFromCenter > nearPoint1[1]:
            nnp1 = (nearPoint1[0], DistFromCenter)
            self.outerPoints[:] = [nnp1 if (p[0] == nearPoint1[0] and p[1] == nearPoint1[1]) else p for p in self.outerPoints]

        if DistFromCenter > nearPoint2[1]:
            nnp2 = (nearPoint2[0], DistFromCenter)
            self.outerPoints[:] = [nnp2 if (p[0] == nearPoint2[0] and p[1] == nearPoint2[1]) else p for p in self.outerPoints]

        if nearPoint1[1] > nearPoint2[1]:
            self.maxSectorG = nearPoint1[1]
        else:
            self.maxSectorG = nearPoint2[1]

        if self.maxSectorG > self.maxOverallG:
            self.maxOverallG = self.maxSectorG
            self.ax2.axes.set_xlim(0, self.maxOverallG)

    def animateGPoints(self, i):  # animates the actual blue G point reading
        global numOfPoints
        self.points.append(self.randomPoint())
        N = self.numOfPoints
        while len(self.points) > self.numOfPoints:
            self.points.pop(0)
        theta_val = [x[0] for x in self.points]
        rad_val = [x[1] for x in self.points]
        ln = self.ax1.plot(theta_val[-N:], rad_val[-N:], 'bo-')
        return ln

    def animateBounds(self, i):  # animate the outer yellow bound points
        self.ax1.cla()
        self.ax1.set_ylim(0, 2)
        self.ax1.axes.set_yticklabels([])
        self.ax1.axes.set_xticklabels([])

        theta_val = [t[0] for t in self.outerPoints]
        rad_val = [r[1] for r in self.outerPoints]
        theta_val.append(theta_val[0])
        rad_val.append(rad_val[0])
        out = self.ax1.plot(theta_val, rad_val, 'y-')

        return out

    def animateBars(self, i):  # animate the lower limit bars
        Nums = [self.maxOverallG, self.maxSectorG, self.currentMaxG]
        self.ax2.axes.set_ylim(0, 1)
        self.ax2.axes.tick_params(left=False, bottom=False)
        self.ax2.axes.set_yticklabels([])

        for i in enumerate(barlist):
            i[1][0].set_width(Nums[i[0]])
        thing2 = self.ax2.plot()

        self.fig.canvas.draw()

        return thing2

    def initGPoints(self):
        points = []
        c = 0
        while c <= self.numOfPoints:  # create initial list of 10 points
            points.append(self.randomPoint())
            c = c + 1

        ox_val = [x[0] for x in points]  # split it so we can plot it
        oy_val = [x[1] for x in points]
        ln = self.ax1.plot(points[0], points[1])

        return ln

    def initBounds(self):  # generate the initial outside grip circle points
        self.outerGridCreate()
        theta_val = [t[0] for t in self.outerPoints]
        rad_val = [r[1] for r in self.outerPoints]
        out = self.ax1.plot(theta_val, rad_val)

        return out

    def initBars(self):
        global barlist
        max_G = 1.0
        current_sec = .4
        current = .3
        p1 = self.ax2.barh(0, max_G, height=2, color='gray')
        p2 = self.ax2.barh(0, current_sec, height=2, color='red')
        p3 = self.ax2.barh(0, current, height=2, color='green')
        barlist = [p1, p2, p3]
        return barlist



def main():
    # define the form layout
    layout = [[sg.Text('Animated Matplotlib', size=(40, 1), justification='center', font='Helvetica 20')],
              [sg.Canvas(size=(640, 480), key='canvas')],
              [sg.ReadButton('Exit', size=(10, 2), pad=((280, 0), 3), font='Helvetica 14')]]

    # create the form and show it without the plot
    window = sg.Window('Demo Application - Embedding Matplotlib In PySimpleGUI').Layout(layout).Finalize()

    canvas_elem = window.FindElement('canvas')
    canvas = canvas_elem.TKCanvas
    mfig = MakeFig()
    i = 0
    while True:
        event, values = window.Read(timeout=10)
        if event is 'Exit' or event is None:
            exit(69)

        # fig = make_fig()
        fig = mfig.fig
        mfig.animateBars(i)
        mfig.animateBounds(i)
        mfig.animateGPoints(i)
        figure_x, figure_y, figure_w, figure_h = fig.bbox.bounds
        figure_w, figure_h = int(figure_w), int(figure_h)
        photo = tk.PhotoImage(master=canvas, width=figure_w, height=figure_h)

        canvas.create_image(640/2, 480/2, image=photo)

        figure_canvas_agg = FigureCanvasAgg(fig)
        figure_canvas_agg.draw()

        # Unfortunately, there's no accessor for the pointer to the native renderer
        tkagg.blit(photo, figure_canvas_agg.get_renderer()._renderer, colormode=2)

        i += 1


if __name__ == '__main__':
    main()