Python Kivy Plots с путаницей MeshLinePlot - PullRequest
0 голосов
/ 06 сентября 2018

Я пытаюсь реализовать графики в реальном времени для измерений в приложении Kivy, но я не понимаю внутреннюю работу библиотеки Kivy Garden.

Моя цель, которую я хочу достичь : я хочу, чтобы внутри ScrollView было несколько графиков, чтобы я мог программно добавлять несколько графиков реального времени из словаря и прокручивать их, если они занимают больше места чем одна высота экрана. Основная проблема, с которой я столкнулся, заключается в том, что график не ведет себя как обычный виджет, а ведет себя как холст. Я уже пытался реализовать это с помощью matplotlib в качестве backend_kivyagg, но мне не удалось установить фиксированный размер для каждого созданного подспотка .

Есть несколько вещей, которые я не понимаю, почему они происходят так, как они происходят.

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()

Вопросы

  1. Внутри класса GraphLayoutApp я создаю два объекта graph и graph2, но если я добавлю их в GridLayout (), появится только один? Как можно добавить несколько графиков?

  2. Также внутри метода сборки класса GraphLayoutApp я создаю две метки. Я хотел сначала отобразить сначала label, а затем график а затем второй ярлык label2. Но мне кажется, что график всегда отображается в левом нижнем углу. Я думаю, это должно сделать с холстом, на котором он нарисован, но я не могу решить его.

1 Ответ

0 голосов
/ 07 сентября 2018

Вот модифицированная версия с некоторыми исправлениями:

Проблема здесь в том, что вы сделали свой Plot наследуемым от Widget, который на самом деле является самым основным виджетом в фреймворке, и, поскольку это не макет, ничего не управляет в дочерних элементах, которые вы добавляете в него, поэтому Graph виджет, который вы добавили к нему, был оставлен с размером / положением по умолчанию (соответственно [100, 100] и [0, 0]), и поэтому они накладывались друг на друга, я использовал RelativeLayout, который устанавливает дочерние элементы по умолчанию на свой собственный размер и положение, поэтому график следует за виджетом. Другое решение состоит в том, чтобы просто сделать Plot наследуемым от Graph, поскольку он является единственным дочерним, и использовать «self.add_plot» вместо «self.graph.add_plot», и переопределить параметры Graph, лучшее решение, вероятно, состоит в создании Правило KV для класса Plot. Но первым решением было минимальное изменение вашего кода.

Общий принцип, который вы пропустили, заключается в том, что в kivy виджеты по умолчанию не ограничены какой-либо позицией / размером, если только их родители не являются макетами, которые специально управляют этим (как GridLayout сделал для ваших меток).

Я также сделал GridLayout автоматически изменяющим размер до минимального размера (определяемого жестко заданным размером, который я вставил во все виджеты), так что у вас действительно есть что прокрутить.

Этот код также очень питонизирован, в 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()
...