Putting a Graph into a Screen

568 views
Skip to first unread message

TH3G3N3S1S

unread,
May 6, 2022, 6:53:28 AM5/6/22
to Kivy users support
Hello everyone,

i am very new to kivy and i wanted to combine two tutorials i followed through. One was displaying a graph using matplotlib and the other was using the ScreenManager to have access to multiple screens with an ActionBar. So i wanted to display a graph in one of those screens.

This is the error i get:
   File "/.../python-screenmanager/screenmanager.py", line 37, in __init__
     box = self.parent.ids.sm.ids.graph_screen
 AttributeError: 'NoneType' object has no attribute 'ids'

Any help is very appreciated, since i found a lot of different answers to my error message but none actually helped solve the problem. Sorry if the formatting is not right, i hope its still readable

Here is my python code:

import kivy
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.metrics import dp, sp

#Graphical Imports
from kivymd.app import MDApp
from kivy.garden.matplotlib.backend_kivyagg import FigureCanvasKivyAgg
import matplotlib.pyplot as plt

x = [ 1, 2, 3, 4, 5]
y = [5, 14, 7, 20, 11]

plt.plot(x,y)
plt.ylabel("y axis")
plt.xlabel("x axis")

class WelcomeScreen(Screen):
pass

class FirstScreen(Screen):
pass

class SecondScreen(Screen):
pass

class ScreenManager(ScreenManager):
pass

class Graph(FloatLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
box = self.parent.ids.sm.ids.graph_screen
box.add_widget(FigureCanvasKivyAgg(plt.gcf()))

def save(self):
pass

class Project(BoxLayout):
pass

kv = Builder.load_file("screenmanager.kv")

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

def build(self, **kwargs):
return Project()

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

here is my kv. file:

#:kivy 2.1.0

<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:
Graph:
id: graph_screen

<SomeMenu_ActionBar@ActionBar>:

ActionView:
id: ActionView

HiddenIcon_ActionPrevious:

ActionGroup:
id: App_ActionGroup
mode: "spinner"
text: "Jump to Screen"

ActionButton:
text: "Welcome Screen"
on_release:
app.root.ids.sm.current = 'welcome'
app.root.ids.sm.transition.direction = "right"
ActionButton:
text: "First Screen"
on_release:
app.root.ids.sm.current = 'first'
app.root.ids.sm.transition.direction = "left"
ActionButton:
text: "Second Screen"
on_release:
app.root.ids.sm.current = 'second'
app.root.ids.sm.transition.direction = "left"
ActionGroup:
id: App_ActionGroup
mode: 'spinner'
text: 'App'

ActionButton:
text: 'Settings'
on_press: app.open_settings()
ActionButton:
text: 'Quit'
on_press: app.get_running_app().stop()
ActionGroup:
id: File_ActionGroup
mode: 'spinner'
text: 'File'

ActionButton:
text: 'Open'
ActionButton:
text: 'Save'
ActionButton:
text: 'Back to Main Menu'
on_release:
app.root.ids.sm.current = 'welcome'
app.root.ids.sm.transition.direction = "right"

<HiddenIcon_ActionPrevious@ActionPrevious>:
title: ''
with_previous: False
app_icon: ''
app_icon_width: 0
app_icon_height: 0
size_hint_x: None
width: len(self.title)*10



<WelcomeScreen>:
name: 'welcome'
Label:
text: 'Welcome Screen'
font_size: sp(50)

<FirstScreen>:
id: first
name: 'first'
Label:
text: 'First Screen'

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

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



 

Elliot Garbus

unread,
May 6, 2022, 11:05:55 AM5/6/22
to kivy-...@googlegroups.com

First -  to paste code to the web site, right click and select paste as plain text, that will preserve the formatting.

 

The issue.  You are trying to access the ids dict in __init__ the ids dict is created when kv is processed use the event on_kv_post()

See: https://kivy.org/doc/stable/api-kivy.uix.widget.html?highlight=on_kv_post#kivy.uix.widget.Widget

 

Additionally the graph is on a screen (self.parent) each screen has an attribute that contains the screen manager.

So self.parent.manager will point to the screenmanager

To access a screen you use the get_screen(‘name’) of the ScreenManager… or

self.parent.manager.get_screen(‘second’).ids.graph_screen

 

Let me know if that solves your issue.

--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/84eda10d-8604-493f-b782-0fa05244cecbn%40googlegroups.com.

 

TH3G3N3S1S

unread,
May 6, 2022, 11:23:45 AM5/6/22
to Kivy users support
Hello, thanks for the fast answer.

when i try
self.parent.manager.get_screen(‘second’).ids.graph_screen
i get the error:
 AttributeError: 'NoneType' object has no attribute 'manager'

since my ScreenManager id is sm i also tried:
box = self.parent.sm.get_screen('second').ids.graph_screen
which gives the error:
 AttributeError: 'NoneType' object has no attribute 'sm'

berk berk

unread,
May 6, 2022, 3:35:36 PM5/6/22
to Kivy users support
I working Python programming about science field. And Kivy really useful for  GUI. I hope this example helps you 



import kivy
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.uix.label import Label
from kivy.lang.builder import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.image import Image,CoreImage      #for create a image with coreimage

import io   #I used io it's simple and useful!

import matplotlib.pyplot as plt   #need matplotlib library

kivy=Builder.load_string("""

<Image_Example>:

    BoxLayout:
        orientation:'vertical'
   
        Button:
            id:click
            text:'display image'
            on_press:root.display_img()  #when it click display image
        Label:
            text:'That is your image'

        Image:
            id:img
            source:''  #image source
           
            allow_stretch:True
           
            keep_ratio:True

""")

class Image_Example(BoxLayout):

    def display_img(self):
        X=[ 1, 2, 3, 4, 5]
        Y= [5, 14, 7, 20, 11]  #your dataset
       
        plt.plot(X,Y)  #craete yourdataset graph
        plt.title("title here")
        plt.xlabel("x-axis label here)")
        plt.ylabel("y-axis label here")
       
        buf=io.BytesIO()
        plt.savefig(buf)  #save your dataset to IoByte
       
        buf.seek(0) #seek your graph
        self.ids.img.texture=CoreImage(buf, ext="png").texture     #display your image
        self.ids.img.reload()
        del buf #then delete created buf

class ImageApp(App):
    def build(self):
        return Image_Example()
       

kv=ImageApp().run()    


example create img.png
6 Mayıs 2022 Cuma tarihinde saat 18:23:45 UTC+3 itibarıyla TH3G3N3S1S şunları yazdı:

Elliot Garbus

unread,
May 7, 2022, 11:22:20 AM5/7/22
to kivy-...@googlegroups.com

If you still have an issue, Share your code, properly formatted.

TH3G3N3S1S

unread,
May 9, 2022, 5:45:38 AM5/9/22
to Kivy users support
Thanks for your example. It ran perfectly on its own, but when i copied it into my own code it didnt work anymore.
This was my error:
 AttributeError: 'super' object has no attribute '__getattr__'
 /home/valentin/.local/lib/python3.8/site-packages/matplotlib/backends/backend_gtk3.py:195: Warning: Source ID 7 was not found when attempting to remove it
   GLib.source_remove(self._idle_draw_id)

Here is my code, hopefully properly formatted. I'm copying my old code and not my code mixed with the suggestion from you. I'm pretty positive something with the ids is making problems, but i cant put my finger on it

python code:
import kivy
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.metrics import dp, sp
from kivy.clock import Clock


#Graphical Imports
from kivymd.app import MDApp
from kivy.garden.matplotlib.backend_kivyagg import FigureCanvasKivyAgg
import matplotlib.pyplot as plt

x = [ 1, 2, 3, 4, 5]
y = [5, 14, 7, 20, 11]

plt.plot(x,y)
plt.ylabel("y axis")
plt.xlabel("x axis")

class WelcomeScreen(Screen):
    pass

class FirstScreen(Screen):
    pass

class SecondScreen(Screen):
    pass

class ScreenManager(ScreenManager):
    pass

class Graph(FloatLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        box = self.parent.sm.get_screen('second').ids.graph_screen

        box.add_widget(FigureCanvasKivyAgg(plt.gcf()))

    def save(self):
        pass

class Project(BoxLayout):
    pass

kv = Builder.load_file("mix.kv")


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

    def build(self, **kwargs):
        return Project()
   
if __name__ == '__main__':
    TestApp().run()

kivy file:

Elliot Garbus

unread,
May 9, 2022, 9:41:45 AM5/9/22
to kivy-...@googlegroups.com

Make the highlighted change below to your code.  I commented out a few things because I did not have some packages installed.

Replace the Label in the highlighted code with your graph.

 

Description:  You have instanced the Graph class, in kv on the second screen.  You need to add the plot to that class (or self in Graph).

 
 
import kivy
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.uix.label import Label
from kivy.metrics import dp, sp
from kivy.clock import Clock

# Graphical Imports
# from kivymd.app import MDApp
# from kivy.garden.matplotlib.backend_kivyagg import FigureCanvasKivyAgg
# import matplotlib.pyplot as plt

x = [1, 2, 3, 4, 5]
y = [
5, 14, 7, 20, 11]

# plt.plot(x, y)
# plt.ylabel("y axis")
# plt.xlabel("x axis")


class WelcomeScreen(Screen):
   
pass


class
FirstScreen(Screen):
   
pass


class
SecondScreen(Screen):
   
pass


class
ScreenManager(ScreenManager):
   
pass


class
Graph(FloatLayout):
   
def __init__(self, **kwargs):
        
super().__init__
(**kwargs)
        
self.add_widget(Label(text='Graph goes here'))
 
    def save(self):
       
pass


class
Project(BoxLayout):
   
pass


kv = Builder.load_file("mix.kv")


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

   
def build(self, **kwargs):
       
return Project()


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

TH3G3N3S1S

unread,
May 9, 2022, 11:41:21 AM5/9/22
to Kivy users support
Thanks a lot that actually works. I dont know why it was built so complicated in the tutorial i watched.

One last question. How can i show multiple Graphs/Widgets on one Screen?
If i build another class like this:
class Graph1(FloatLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        # box = self.parent.sm.get_screen('second').ids.graph_screen
        self.add_widget(FigureCanvasKivyAgg(plt.gcf()))


class Graph2(FloatLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        # box = self.parent.sm.get_screen('second').ids.graph_screen
        self.add_widget(FigureCanvasKivyAgg(plt.gcf()))

and add Graph2 to the kv-file like this:

ScreenManager:
        id: sm
        WelcomeScreen:
        FirstScreen:
        SecondScreen:
            Graph1:
            Graph2:

<Graph1>:
    BoxLayout:
        size_hint_y: .5
        pos_hint: {"top": 1}

<Graph2>:
    BoxLayout:
        size_hint_y: .5
        pos_hint: {"bottom": 1}

i only see one Graph but not the other

Elliot Garbus

unread,
May 9, 2022, 12:50:33 PM5/9/22
to kivy-...@googlegroups.com

You are using a FloatLayout, a float layout positions it’s children relative to the Window coordinates.  You are putting your graphs on top of one another.

 

You can change the Graph to be a Relative Layout and put 2 graphs in BoxLayout on the Screen.

class Graph(RelativeLayout):
   
def __init__(self, **kwargs):
       
super().__init__(**kwargs)
       
self.add_widget(Label(text='Graph goes here'))

   
def save(self):
       
pass

 

and in kv:

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

 

Looking at Graph, I would be inclined define Graph as a BoxLayout. 

TH3G3N3S1S

unread,
May 10, 2022, 6:57:16 AM5/10/22
to Kivy users support
Thanks a lot for your help. I guess i don't have anymore questions
Reply all
Reply to author
Forward
0 new messages