Как иметь подкласс DataFrame (pandas) и автоматически обновляемый Widget (kivy) при изменении DF? - PullRequest
0 голосов
/ 27 октября 2019

Это о двух, как-то связанных проблемах. С одной стороны, речь идет о создании правильного подкласса, включающего метод «change_DF» для объекта DataFrame (DF) панд. (Веро 1 )С другой стороны, речь идет об использовании on_ {property} и ObjectProperty от kivy правильным способом, поэтому он обнаруживает изменения в упомянутой DF. (Prob 2 )

Относительно Prob1 есть несколько учебных пособий, например, от самой панды:https://pandas.pydata.org/pandas-docs/stable/development/extending.html#extending-subclassing-pandasи некоторые очень богатые детали, такие как:http://devanla.com/case-for-inheriting-from-pandas-dataframe.html
Подклассы Pandas DataFrame, обновления? (@stackoverflow)К сожалению, содержание, которое мне не известно на данный момент (придется подробно изучить этот класс / super / property / * args / ** kwargs / etc.… Не стесняйтесь учить меня в контексте данного фрагмента кода). ..!

Относительно Prob2 Я чувствую себя немного застрявшим с Prob1, потому что кажется, что вопрос заключается в том, что должен сравнивать kivy при проверке, были ли внесены какие-либо «соответствующие» измененияв "binded_kDF" ... (ну, мне кажется, что мне не хватает дополнительных знаний о принципах мощного EventDispatcher Kivy ... даже больше, чтобы изучать и изучать, очевидно)

Часть кода, о которой идет речь,готов к запуску с Py3.7.4:

from kivy.app import App
import pandas as pd
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.properties import ObjectProperty

class KivyDataFrame(pd.DataFrame):
    @property
    def _constructor(self):
        return KivyDataFrame
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
    def change_DF(self, data):
#        self.data = data                        # [Problem1] not how it works...
        self.update(pd.DataFrame(data))          # ...and this one only works given (same structure with) same col-names

class KivySheet(GridLayout):
    binded_kDF = ObjectProperty()
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.cols=2
        self.rows=2
        self.counter = 1
    def bind_kDF(self, kDF):
        self.binded_kDF = kDF
    def create_Sheet(self, *args):
        print(self.binded_kDF)
        for row in self.binded_kDF.to_numpy():
            for value in row:
                self.add_widget(Label(text=str(value)))
    def update_Sheet(self, *args):
        self.clear_widgets()
        self.create_Sheet()
    def on_binded_kDF(self, *args):               # [Problem2] not called automatically when pressing Button (calling it beyond initiation; counter=2)
        print("counter:", self.counter)
        self.update_Sheet()
        self.counter+=1

class AppFrame(BoxLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.orientation="vertical"
        self.kDF = KivyDataFrame(data={'col1': [1, 2], 'col2': [3, 4]})
        self.kSh = KivySheet()
        self.kSh.bind_kDF(self.kDF)
        self.add_widget(self.kSh)
        self.add_widget(Button(text="«change kDF»", on_press=lambda u:self.change_kDF()))
    def change_kDF(self):
        self.kDF.change_DF(data={'col1': [5, 6], 'col2': [7, 8]})  # change col-names and it doesn't work anymore (see Problem 1) 
#        self.kSh.update_Sheet()                                   # necessary to have the wanted changing-effect (why Problem 2 has to be solved)

class MySheetApp(App):
    def build(self):
        return AppFrame()
if __name__ == '__main__':
    MySheetApp().run()

Для обеих проблем я прокомментировал строку, которая не работала ( 1 ) или является обходным решением ( 2 ). Скомментируйте последнее, и вы увидите ожидаемый результат (включая «counter: 2»), который я ищу.

Сообщения об ошибках / предупреждениях, которые я получил относительно Prob1 (используя self.data = data ): UserWarning: Pandas не позволяет создавать столбцы с помощью нового имени атрибута - см. https://pandas.pydata.org/pandas-docs/stable/indexing.html#attribute-access

... и относительно Prob2 : [ПРЕДУПРЕЖДЕНИЕ] [Свойство] Не удалось сравнить значения, поскольку " init () принимает 1 позиционный аргумент, но 2 задано". Чтобы избежать этого, рекомендуется установить для Force_dispatch значение True.

...