简体   繁体   English

Kivy:使用滑块更新Matplotlib画布

[英]Kivy: update matplotlib canvas with a slider

I need to create a slider which updates a matplotlib figure. 我需要创建一个更新matplotlib图形的滑块。 So far I have this, main.py: 到目前为止,我有这个main.py:

from kivy.app import App
from kivy.properties import ObjectProperty
from kivy.uix.boxlayout import BoxLayout
import numpy as np
import matplotlib.pyplot as plt
from kivy.garden.matplotlib.backend_kivyagg import FigureCanvasKivyAgg

class Container(BoxLayout):
    display = ObjectProperty()
    def __init__(self, *args, **kwargs):
        global canvas
        super(Container, self).__init__(**kwargs)
        lum_img = np.random.rand(10,10)
        plt.imshow(lum_img, cmap="gray")
        plt.colorbar() 
        canvas = FigureCanvasKivyAgg(plt.gcf())
        self.ids.box_display.add_widget(canvas)
        canvas.draw()

    def add_one(self, value):
        lum_img = np.random.rand(10,10)
        plt.imshow(lum_img, cmap="gray")
        plt.colorbar() 
        canvas.draw()

        self.display.text = str(round(value,2))



class MainApp(App):
    def build(self):
        self.title = 'Image and slider app'

        return Container()


if __name__ == "__main__":
    app = MainApp()
    app.run()

And the main.kv: 和main.kv:

<Container>:
    display: display
    id: main_display
    orientation: "vertical"

    BoxLayout:
        id: box_display
        orientation: "vertical"


        Slider:
            id: slider_image
            min: 0
            max: 1
            value: 0.5
            on_value: root.add_one(value = slider_image.value)

    Label:
        id: display
        font_size: dp(50)
        text: '0'

The behaviour is not as expected, instead of updating the image canvas it just move it! 该行为不符合预期,它只是移动图像而不是更新图像画布! I think that the error is to declare the canvas as a global variable, but I do not know how to update it without doing this. 我认为错误是将画布声明为全局变量,但不执行此操作我不知道如何更新它。

Any idea? 任何想法?

You code is actually creating new plots, but they are not positioned well and overlap each other. 您的代码实际上是在创建新的图,但是它们的位置不正确并且彼此重叠。 One way to correct that problem is to use plt.subplot() . 解决该问题的一种方法是使用plt.subplot() That requires knowing in advance how many subplots you will add. 这需要预先知道要添加多少个子图。 Here is a modified version of your code that uses this approach (I included the .kv as a string just for my own convenience): 这是使用此方法的代码的修改版本(为方便起见,我将.kv作为字符串包含在内):

from kivy.app import App
from kivy.lang import Builder
from kivy.properties import ObjectProperty
from kivy.uix.boxlayout import BoxLayout
import numpy as np
import matplotlib.pyplot as plt
from kivy.garden.matplotlib.backend_kivyagg import FigureCanvasKivyAgg

Builder.load_string('''
<Container>:
    display: display
    id: main_display
    orientation: "vertical"

    BoxLayout:
        id: box_display
        orientation: "vertical"


        Slider:
            id: slider_image
            min: 0
            max: 1
            value: 0.0
            on_value: root.add_one(value = slider_image.value)

    Label:
        id: display
        font_size: dp(50)
        text: '0'
''')

class Container(BoxLayout):
    display = ObjectProperty()
    def __init__(self, *args, **kwargs):
        global canvas
        super(Container, self).__init__(**kwargs)
        self.index = 1    # index of the current plot
        self.max_plots = 5     # maximum number of subplots
        self.old_slider_value = 0.0   # starting value of the slider
        lum_img = np.random.rand(10,10)
        plt.subplot(1, self.max_plots, self.index)     # create the first subplot
        plt.imshow(lum_img, cmap="gray")
        plt.colorbar()
        canvas = FigureCanvasKivyAgg(plt.gcf())
        self.ids.box_display.add_widget(canvas)
        canvas.draw()

    def add_one(self, value):
        # only make a new subplot if the slider has moved at least 0.2
        if (value - self.old_slider_value) > 1.0/self.max_plots and self.index < self.max_plots:
            self.old_slider_value = value
            self.index += 1
            plt.subplot(1, self.max_plots, self.index)     # make new subplot
            lum_img = np.random.rand(10,10)
            plt.imshow(lum_img, cmap="gray")
            plt.colorbar()
            plt.tight_layout()     # arrange the subplots a bit to eliminate overlaps
            canvas.draw()

        self.display.text = str(round(value,2))



class MainApp(App):
    def build(self):
        self.title = 'Image and slider app'

        return Container()


if __name__ == "__main__":
    app = MainApp()
    app.run()

Misunderstood what you wanted (my error). 误解了您想要的东西(我的错误)。 If you do not want to create new plots, but just update the existing one, you only need to add a call to plt.clf() in your add_one() method before you do any additional plotting. 如果您不想创建新的绘图,而只是更新现有的绘图,则只需在执行其他绘图之前在add_one()方法中添加对plt.clf()的调用即可。 This clears the current figure, and allows you to replace it with a new one. 这将清除当前图形,并允许您将其替换为新图形。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM