'How to put a Graph into a Screen(Manager) with kivy

I have 3 Screens in my kivy application and in the second screen i want to put a graph which is a widget. I have my own class for this graph. The goal is do display 3 separate graphs in one screen.

I'm pretty sure there is some problem with the id from the class Graph. I tried to use self.ids.get_screen or just copying everything from the class Graph to the class SecondScreen. Sometimes i get a different error but normally this one.

Can maybe someone explain IDs to me? I think i am very confused what to do when i have to use an id from one class in another. Sadly the other questions with the same error didn't really help

Thanks a lot for helping!

This is my error:

Traceback (most recent call last):
   File "kivy/properties.pyx", line 961, in kivy.properties.ObservableDict.__getattr__
 KeyError: 'boxgraph'
 
 During handling of the above exception, another exception occurred:
 
 Traceback (most recent call last):
   File "/home/valentin/Desktop/Masterarbeit/python-screenmanager/screenmanager.py", line 57, in <module>
     TestApp().run()
   File "/home/valentin/.local/lib/python3.8/site-packages/kivy/app.py", line 954, in run
     self._run_prepare()
   File "/home/valentin/.local/lib/python3.8/site-packages/kivy/app.py", line 924, in _run_prepare
     root = self.build()
   File "/home/valentin/Desktop/Masterarbeit/python-screenmanager/screenmanager.py", line 54, in build
     return Project()
   File "/home/valentin/.local/lib/python3.8/site-packages/kivy/uix/boxlayout.py", line 145, in __init__
     super(BoxLayout, self).__init__(**kwargs)
   File "/home/valentin/.local/lib/python3.8/site-packages/kivy/uix/layout.py", line 76, in __init__
     super(Layout, self).__init__(**kwargs)
   File "/home/valentin/.local/lib/python3.8/site-packages/kivy/uix/widget.py", line 366, in __init__
     self.apply_class_lang_rules(
   File "/home/valentin/.local/lib/python3.8/site-packages/kivy/uix/widget.py", line 470, in apply_class_lang_rules
     Builder.apply(
   File "/home/valentin/.local/lib/python3.8/site-packages/kivy/lang/builder.py", line 540, in apply
     self._apply_rule(
   File "/home/valentin/.local/lib/python3.8/site-packages/kivy/lang/builder.py", line 662, in _apply_rule
     self._apply_rule(
   File "/home/valentin/.local/lib/python3.8/site-packages/kivy/lang/builder.py", line 660, in _apply_rule
     child.apply_class_lang_rules(
   File "/home/valentin/.local/lib/python3.8/site-packages/kivy/uix/widget.py", line 470, in apply_class_lang_rules
     Builder.apply(
   File "/home/valentin/.local/lib/python3.8/site-packages/kivy/lang/builder.py", line 540, in apply
     self._apply_rule(
   File "/home/valentin/.local/lib/python3.8/site-packages/kivy/lang/builder.py", line 658, in _apply_rule
     child = cls(__no_builder=True)
   File "/home/valentin/Desktop/Masterarbeit/python-screenmanager/screenmanager.py", line 40, in __init__
     box = self.ids.boxgraph
   File "kivy/properties.pyx", line 964, in kivy.properties.ObservableDict.__getattr__
 AttributeError: 'super' object has no attribute '__getattr__'

This are some code snippets:

python code:

class ScreenManager(ScreenManager):
    pass

class Project(BoxLayout):
    pass

class Graph(FloatLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        box = self.ids.boxgraph
        box.add_widget(FigureCanvasKivyAgg(plt.gcf()))

    def save(self):
        pass

Builder.load_file("screenmanager.kv")

class TestApp(MDApp):
    title = "Kivy Project"

    def build(self):
        self.theme_cls.theme_style ="Dark"
        self.theme_cls.primary_palette = "BlueGray"
        return Project()
    
if __name__ == '__main__':
    TestApp().run()

kivy code:

<Project>:
    orientation: "vertical"

    canvas.before:
        Color:
            rgb: .6, .6, .6
        Rectangle:
            pos: self.pos
            size: self.size
    
    SomeMenu_ActionBar:
        id: ActionBar

    ScreenManager:
        id: sm
        WelcomeScreen:
        FirstScreen:
        SecondScreen:

 /.../

<SecondScreen>:
    id: second
    name: 'second'
    Graph:

<Graph>:
    id: boxgraph
    
    BoxLayout:
        size_hint_y: .9
        pos_hint: {"top": 1}
        
    BoxLayout:
        size_hint_y: .1
        TextInput:
            id: name
            multiline: False

        Button:
            text: "Save"
            on_release: root.save()

EDIT: ok i figured some stuff out. The ids library contains those ids

{'ActionBar': <WeakProxy to <kivy.factory.SomeMenu_ActionBar object at 0x7f9ffc677c10>>, 'sm': <WeakProxy to <kivy.uix.screenmanager.ScreenManager object at 0x7f9ff4175820>>}

so i think i need to add the graph id there too. Still not sure how, but im still on it.

I deleted the Graph: from Second Screen. Added Graph: with an id to ScreenManager:

ScreenManager:
     id: sm
     WelcomeScreen:
     FirstScreen:
     SecondScreen:
         Graph:
             id: graph_screen

Now i have this AttributeError:

AttributeError: 'NoneType' object has no attribute 'ids'



Solution 1:[1]

Ok i found the answer

Here is only the changed parts of my code: python file:

class Graph(BoxLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.add_widget(FigureCanvasKivyAgg(plt.gcf()))

kv-file:

ScreenManager:
        id: sm
        WelcomeScreen:
        FirstScreen:
        SecondScreen:

<SecondScreen>:
    id: second
    name: 'second'
    BoxLayout:
        orientation: "vertical"
        Graph:

I dont need a definition of Graph in the kv-File since everything is handled in the python file

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1