I created code which places Kivy objects and all their variables in a dataframe. The idea was once the object has served its purpose I can drop the row from the dataframe and delete the object from memory.
The simplified example below will require a -pip install of Kivy and creation of the .kv file specified. In the example an object is generated on app initialisation. A count is incremented with the u key. Once the count reaches the y seed value of the object in the dataframe that row is dropped from the dataframe. However, the object remains on screen. The code prints the counter value and dataframe to track what is happening.
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.relativelayout import RelativeLayout
import pandas as pd
from kivy.graphics import Color, Quad
class GUI(RelativeLayout):
"""Variable creation"""
"""Y axis setting"""
vertical_lines = 10
vertical_line_spacing = 1
"""X axis setting"""
horizontal_line_count = 10
horizontal_line_spacing = 1
"""Object settings"""
seed_count = 1
objects = pd.DataFrame()
counter = -1
"""Initialise app"""
def __init__(self, **kwargs):
super(GUI, self).__init__(**kwargs)
"""GUI creation"""
self.create_objects()
self.update_objects()
"""Keyborad bindings"""
self._keyboard = Window.request_keyboard(self.keyboard_closed, self)
self._keyboard.bind(on_key_down=self.on_keyboard_down)
def keyboard_closed(self):
self._keyboard.unbind(on_key_down=self.on_keyboard_down)
self._keyboard = None
def on_keyboard_down(self, keyboard, keycode, text, modifiers):
if keycode[1] == 'u':
self.counter += 1
self.destroy_objects()
print("counter at: ", self.counter)
print(self.objects['y seed'])
return True
def create_objects(self):
"""Create vertical lines"""
with self.canvas:
Color(0, 1, .8)
for i in range(self.seed_count):
data = {'element 1': Quad(), 'element 2': Quad(),
'x seed': 0, 'y seed': i}
creation = pd.DataFrame(data, index=[0])
self.objects = self.objects.append(creation)
return self.objects
def update_objects(self):
for i in range(self.seed_count):
element_1 = self.objects['element 1'].iloc[i]
element_2 = self.objects['element 2'].iloc[i]
y_spacing = self.vertical_line_spacing * self.width
x_spacing = self.horizontal_line_spacing * self.height
xmin, ymin = self.objects['x seed'].iloc[i], self.objects['y seed'].iloc[i]
x1a, y1a = (xmin, ymin)
x2a, y2a = (xmin - y_spacing / 2, ymin + x_spacing)
x3a, y3a = (xmin + y_spacing * 1.5, ymin + x_spacing)
x4a, y4a = (xmin + y_spacing, ymin)
x1b, y1b = x2a, y2a
x2b, y2b = x1a, ymin + 2 * x_spacing
x3b, y3b = x4a, ymin + 2 * x_spacing
x4b, y4b = x3a, y3a
element_1.points = [x1a, y1a, x2a, y2a, x3a, y3a, x4a, y4a]
element_2.points = [x1b, y1b, x2b, y2b, x3b, y3b, x4b, y4b]
def destroy_objects(self):
try:
for i in range(len(self.objects)):
if self.objects['y seed'].iloc[i] < self.counter:
self.objects = self.objects.drop(self.objects.index[i])
except IndexError:
pass
class ExampleApp(App):
pass
ExampleApp().run()
This requires the following .kv file to run:
GUI:
<GUI>:
I think the problem may relate to dataframes creating copies of themselves rather than writing over the origonals.
How can I delete the object while still maintaining the DataFrame structure?
Is there a better way to manage objects and related variables to allow for editing and deleting en mass?
I have reverted to using lists to store objects.
Objects can be cleared with the canvas.remove() command and variable information can be deleted from lists iteratively. This means you can only delete one at a time when you iteratre through the list which is why I avoided it in the first place.
Using a while loop to contain the delete query counters indexing errors by shrinking the index on the fly.