0

I am new to Python (using 3.4.2) and Kivy (v1.11.0 dev0) and I am trying to make an app with two screens. In one screen the user can set pump settings and in the next screen the user can see a live graph of pressure that is recorded from pressure sensors.

I have been able to make an app where a graph plots data live and I have been able to make another (completely separate) app where a user can select the pump settings and switch to another screen.

My problem is that I can't seem to combine the two into one app. Maybe part of my problem is that I used kivy language for the ScreenManager and settings app and not the live graph, but I'm not sure.

So, my question is: is there a way in which I can integrate my Matplotlib kivy app (seen below 'Graph' class) into the my main program to get one app where on one screen settings are selected and in another screen the graph is shown?

As a note: I was able to get the example from https://github.com/jeysonmc/kivy_matplotlib running, but I couldn't figure out how to alter to code to get it to plot live data.

Here are my programs:

Setting App, with an attempt to incorporate the live graph in "Graph" class. Let me know if I should post the text file. Since I don't have the sensors yet, it's just two columns of random numbers for testing:

from kivy.garden.matplotlib.backend_kivyagg import FigureCanvasKivyAgg
from matplotlib.figure import Figure
import matplotlib as mpl
from kivy_matplotlib import MatplotFigure, MatplotNavToolbar
import matplotlib.pyplot as plt

from kivy.app import App
from kivy.base import runTouchApp
from kivy.lang import Builder
from kivy.properties import ListProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.clock import Clock
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
import numpy as np


class FirstScreen(Screen):
    pass

class PlotScreen(Screen):
    pass

class Graph(BoxLayout):

    def build(self):
        box = BoxLayout(orientation="vertical")
        a = Button(text="Go Back", height = 40, size_hint_y=None)
        self.graf = plt.gcf()
        plt.ylabel('Pressure')
        plt.xlabel('Time')
        box.add_widget(FigureCanvasKivyAgg(self.graf))
        box.add_widget(a)
        Clock.schedule_interval(self.GetData,1/25)
        return box

    def GetData(self, *args):  
        graph_data = open('Mitrample.txt','r').read()   #opens file to read data
        lines = graph_data.split('\n')
        self.x = []
        self.y = []
        for line in lines:
            if len(line) > 1:
                x_Help, y_Help = line.split(',')
                self.x.append(x_Help)
                self.y.append(y_Help)
        plt.plot(self.x,self.y)
        self.graf.canvas.draw()  #updates graph

class MyScreenManager(ScreenManager):
    pass

root_widget = Builder.load_file("two_face.kv")

class ScreenManagerApp(App):
    def build(self):
        return root_widget

ScreenManagerApp().run()

.kv file:

#:import FadeTransition kivy.uix.screenmanager.FadeTransition

MyScreenManager:
    transition: FadeTransition()
    FirstScreen:
    PlotScreen:

<FirstScreen>:
    name: 'first'
    BoxLayout:
        orientation: 'vertical'
        padding: 5
        spacing: 5
        Label:
            text: 'Settings'
            font_size: 30
        BoxLayout:
            Label:
                text: 'Motor Speed'
                font_size: 30
            ToggleButton:
                text: 'Very Slow'
                font_size: 30
                group: "please1"
                on_release: #root.Light_Run(self.state)
            ToggleButton:
                text: 'Slow'
                font_size: 30
                group: "please1"
                on_release: #root.Light_Run(self.state)
            ToggleButton:
                text: 'Medium'
                font_size: 30
                group: "please1"
                on_release: #root.Light_Run(self.state)
            ToggleButton:
                text: 'Fast'
                font_size: 30
                group: "please1"
                on_release: #root.Light_Run(self.state)
            ToggleButton:
                text: 'Very Fast'
                font_size: 30
                group: "please1"
                on_release: #root.Light_Run(self.state)


        BoxLayout:
            Label:
                text: 'Water Pumped'
                font_size: 30

            ToggleButton:
                text: '50 mL'
                font_size: 30
                group: "please2"

            ToggleButton:
                text: '60 mL'
                font_size: 30
                group: "please2"

            ToggleButton:
                text: '70 mL'
                font_size: 30
                group: "please2"

        BoxLayout:
            Label:
                text: 'Iterations'
                font_size: 30

            ToggleButton:
                text: '1'
                font_size: 30
                group: "please3"

            ToggleButton:
                text: '5'
                font_size: 30
                group: "please3"

            ToggleButton:
                text: '10'
                font_size: 30
                group: "please3"

            ToggleButton:
                text: '30'
                font_size: 30
                group: "please3"

            ToggleButton:
                text: '50'
                font_size: 30
                group: "please3"

        BoxLayout:
            Button:
                text: 'Go to Plot'
                font_size: 30
                on_release: app.root.current = 'second'
            Button:
                text: 'Lets Pump :)'
                font_size: 30
<PlotScreen>:
    name: 'second'
    BoxLayout:
        orientation: 'vertical'
        padding: 5
        spacing: 5
        Label:
            text: 'Settings'
            font_size: 30
    Graph
Snorkels
  • 1
  • 2

1 Answers1

0

I don't know, if this helps you, but I modified your code to see at least the sinus function from the example:

fig = mpl.figure.Figure(figsize=(2, 2))
t = np.arange(0.0, 100.0, 0.01)
s = np.sin(0.08 * np.pi * t)
axes = fig.gca()
axes.plot(t, s)
axes.set_xlim(0, 50)
axes.grid(True)


class ScreenManagerApp(App):
    def build(self):
        figure_wgt = root_widget.get_screen('second').ids['figure_wgt']
        figure_wgt.figure = fig
        return root_widget

And in two_face.kv:

<PlotScreen>:
    name: 'second'
    BoxLayout:
        orientation: 'vertical'

        MatplotFigure:
            id: figure_wgt
            size_hint: 1, 0.7

        MatplotNavToolbar:
            id: navbar_wgt
            size_hint: 1, 0.3
            figure_widget: figure_wgt

This does not enables you to display data dynamically, but maybe you can use kivy.clock to update the data.

Please let me know how you solved your problem.

mss
  • 348
  • 2
  • 12
  • Thanks for your help! I've update my program per your recommendation and getting the graph to show up on the second screen is a major improvement. I sort of got the data to graph "live" but it only updates the graph when I change the window size, so it doesn't fully work. I used mostly the "GetData" function that I originally posted and the kivy.clock in the build function of the Screen ManagerApp to do this. I've tried adding '.draw()' to the code (sorta guess and check) so it would update on its own but that only led to more errors. I can post my code/exactly what I did if that would help. – Snorkels Jul 30 '18 at 09:35