How to display matplotlib graphs within kivy BoxLayout | RelativeLayout framework

7,280 views
Skip to first unread message

David Daiku Trowbridge

unread,
Jul 2, 2016, 11:54:06 AM7/2/16
to Kivy users support
I am trying to write an application that can display graphs within a vertical BoxLayout. Starting with an example that displays a Button, Label and another button in three rows, I'm hoping to replace the top button with a graph. Below is my code for a framework and the corresponding kvlang file.

from matplotlib import pyplot as plt
from kivy.app import App
from kivy.properties import ObjectProperty, StringProperty
#from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.core.window import Window
from kivy.graphics import Color
from kivy.properties import NumericProperty, ReferenceListProperty,\
   
ObjectProperty
from kivy.vector import Vector
from kivy.clock import Clock

class LineBuilder:
    n
= 0
    def __init__(self, line):
       
self.line = line
       
self.xs = list(line.get_xdata())
       
self.ys = list(line.get_ydata())
       
self.cid = line.figure.canvas.mpl_connect('button_press_event', self)
#        self.cid = line.figure.canvas.mpl_connect('motion_notify_event', self)

    def __call__(self, event):
#        print 'click', event
        if event.inaxes!=self.line.axes: return
        print 'n=', self.n
       
self.n += 1
        self.xs.append(event.xdata)
       
self.ys.append(event.ydata)
       
self.line.set_data(self.xs, self.ys)
       
self.line.figure.canvas.draw()

class GT(BoxLayout):
   
"""Receives custom widget from corresponding <name>.kv file"""
    label_widget = ObjectProperty()
    graph_widget
= ObjectProperty()
   
def __init__(self, **kwargs):
       
super(GT, self).__init__(**kwargs)
       
Window.clearcolor = (0.9, 0.93, 0.95, 1)

   
def do_action(self):
       
self.label_widget.text = 'Graph was clicked.' # This works
        self.info = 'Important info!'


class frameworkApp(App):
   
def build(self):
       
return GT()
   
"""I want to invoke matplotlib for graphs, but have them appear
    within a RelativeLayout of a BoxLayout, not in a separate window.
    Note: The 8 icons above the pyplot graph (Figure 1) are not necessary here."""
    fig = plt.figure()
    ax
= fig.add_subplot(111)
    ax
.set_title('click to build line segments')
    line
, = ax.plot([0], [0])  # empty line
    linebuilder = LineBuilder(line)
    plt
.show()


if __name__ == '__main__':
    frameworkApp
().run()

#:kivy 1.9.1

<GT>: # Name of the class in main
    label_widget
: my_custom_label
   
#graph_widget: my_graph # attempt to create a custom widget for graphs

   
BoxLayout:
        orientation
: 'vertical'

       
RelativeLayout:
           
# I would like to replace red Button with a matplolib graph in the top row
            plt
:
               
#id: my_graph # This is wrong: invalid syntax
               
#size_hint: (1, 1)
           
Button: # red Button
                background_normal
: ''
                background_color
: 0.6, 0.15, 0.15, 1.
                text
: 'Graph'
                on_press
: root.do_action()
#                on_touch_down: print('Graph Relative: {}'.format(args[1].pos))
       
RelativeLayout:
           
Label:
                id
: my_custom_label
                color
: 0.9, 0.4, 0, 0.8 # This works
                text
: 'My label before Graph button is pressed'
                text_size
: root.width, None
#                on_touch_down: print('Text Relative: {}'.format(args[1].pos))
       
RelativeLayout:
           
Button:
                background_normal
: ''
                background_color
: 0.3, 0.15, 0.75, 1.
                text
: 'Blue Button'
#                on_touch_down: print('Bluebutton Relative: {}'.format(args[1].pos))


Can anyone give me some guidance on how to accomplish this?

Thanks!

David

Bill Janssen

unread,
Jul 6, 2016, 9:08:44 PM7/6/16
to Kivy users support
Kivy garden has a "matplotlib" package which can display matplotlib plots, using Kivy graphics.  You replace your red button with an instance of that widget.

    import matplotlib
    matplotlib
.use("module://kivy.garden.matplotlib.backend_kivy")
   
from kivy.garden.matplotlib import FigureCanvasKivyAgg

Then do your plotting and output it with this (not sure how you'd do it in kv):

       box.add_widget(FigureCanvasKivyAgg(plt.gcf()))

Look at https://andnovar.wordpress.com/ for more info.

Bill

David Daiku Trowbridge

unread,
Jul 14, 2016, 11:55:19 PM7/14/16
to Kivy users support
Thanks for the helpful guidance, Bill. Please see my recent post, 

Reply all
Reply to author
Forward
0 new messages