Python Kivy 图与 MeshLinePlot 混淆

Python Kivy Plots with MeshLinePlot confusion

我正在尝试为 Kivy 应用程序实现实时测量图,但我不了解 kivy 花园库的内部工作原理。

我想要实现的目标:我想在 ScrollView 中有多个图,这样我就可以从字典中以编程方式添加多个实时图,并且如果它们占据 space 多于一个屏幕高度,则滚动浏览它们。我遇到的主要问题是 Graph 的行为不像普通的 Widget,而是像 canvas。我已经尝试使用 matplotlib 将其实现为 backend_kivyagg,但我未能为每个 subplot that I created.

设置固定大小

有很多事情我不明白为什么会这样发生。

from math import sin, cos

from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.scrollview import ScrollView
from kivy.uix.widget import Widget

from kivy.garden.graph import Graph, MeshLinePlot


class Plot(Widget):
    def __init__(self):
        super(Plot, self).__init__()
        self.graph = Graph(xlabel="x", ylabel="y", x_ticks_minor=5, x_ticks_major=25, y_ticks_major=1,
                           y_grid_label=True, x_grid_label=True, x_grid=True, y_grid=True,
                           xmin=-0, xmax=100, ymin=-1, ymax=1, draw_border=False)
        # graph.size = (1200, 400)
        # self.graph.pos = self.center

        self.plot = MeshLinePlot(color=[1, 1, 1, 1])
        self.plot.points = [(x, sin(x / 10.)) for x in range(0, 101)]
        self.plot2 = MeshLinePlot(color=[1, 0, 0, 1])
        self.plot2.points = [(x, cos(x / 10.)) for x in range(0, 101)]
        self.add_widget(self.graph)

        self.graph.add_plot(self.plot)
        self.graph.add_plot(self.plot2)


class GraphLayoutApp(App):

    def build(self):
        scroll_view = ScrollView()
        grid_layout = GridLayout(cols=1, row_force_default=True, padding=20, spacing=20)
        graph = Plot()
        graph2 = Plot()
        label = Label(text="Hello World!")
        label2 = Label(text="Hello World!")
        grid_layout.add_widget(label)
        grid_layout.add_widget(graph)
        grid_layout.add_widget(label2)
        grid_layout.add_widget(graph2)
        scroll_view.add_widget(grid_layout)

        return scroll_view


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

Questions:

  1. Inside the class GraphLayoutApp I create two objects graph and graph2 but if I add them to the GridLayout() only one does appear? How can I add multiple graphs?

  2. Also Inside the build method of the class GraphLayoutApp I create two lables. I wanted to first display the first label then the graph and then the second label label2. But it seems to me that the graph is always displayed in the lower left corner. I guess this has to do with the canvas on which it is drawn, but I cannot solve it.

这是修正了一些问题的修改版本:

这里的问题是您让 Plot 继承自 Widget,它实际上是框架中最基本的小部件,并且由于它不是布局,因此不会管理您添加的 children 中的任何内容到它,所以你添加到它的 Graph 小部件被保留在默认值 size/position (分别是 [100, 100] 和 [0, 0]),所以它们相互堆叠,我用RelativeLayout,它默认将 children 设置为它自己的大小和位置,因此 Graph 跟随 widget。另一种解决方案是简单地使 Plot 继承自 Graph,因为它是唯一的 child,并使用“self.add_plot”而不是“self.graph.add_plot”,并覆盖 Graph 参数,最好解决方案可能是为 Plot class 创建一个 KV 规则。但第一个解决方案是对您的代码进行最小的更改。

您错过的一般原则是,在 kivy 中,小部件默认情况下不受任何限制 position/size,除非它们的 parents 是专门管理它的布局(就像 GridLayout 为您的标签所做的那样) .

我还让 GridLayout 自动调整自己的大小为 minimum_size(由我放入所有小部件的硬编码大小决定),所以你实际上有东西可以滚动。

这段代码也很python-driven,在kivy中,你通常想用KV做更多的事情,而不是用add_widget静态的东西

from math import sin, cos

from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.scrollview import ScrollView
from kivy.uix.widget import Widget
from kivy.uix.relativelayout import RelativeLayout

from kivy_garden.graph import Graph, MeshLinePlot


class Plot(RelativeLayout):
    def __init__(self, **kwargs):
        super(Plot, self).__init__(**kwargs)
        self.graph = Graph(xlabel="x", ylabel="y", x_ticks_minor=5, x_ticks_major=25, y_ticks_major=1,
                           y_grid_label=True, x_grid_label=True, x_grid=True, y_grid=True,
                           xmin=-0, xmax=100, ymin=-1, ymax=1, draw_border=False)
        # graph.size = (1200, 400)
        # self.graph.pos = self.center

        self.plot = MeshLinePlot(color=[1, 1, 1, 1])
        self.plot.points = [(x, sin(x / 10.)) for x in range(0, 101)]
        self.plot2 = MeshLinePlot(color=[1, 0, 0, 1])
        self.plot2.points = [(x, cos(x / 10.)) for x in range(0, 101)]
        self.add_widget(self.graph)

        self.graph.add_plot(self.plot)
        self.graph.add_plot(self.plot2)


class GraphLayoutApp(App):

    def build(self):
        scroll_view = ScrollView()
        grid_layout = GridLayout(cols=1, padding=20, spacing=20, size_hint_y=None)
        grid_layout.bind(minimum_size=grid_layout.setter('size'))
        graph = Plot(size_hint_y=None, height=500)
        graph2 = Plot(size_hint_y=None, height=500)
        label = Label(text="Hello World!", size_hint_y=None)
        label2 = Label(text="Hello World!", size_hint_y=None)
        grid_layout.add_widget(label)
        grid_layout.add_widget(graph)
        grid_layout.add_widget(label2)
        grid_layout.add_widget(graph2)
        scroll_view.add_widget(grid_layout)

        # return grid_layout
        return scroll_view


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