*große* daten effektiv darstellen - modellierung?

Plattformunabhängige GUIs mit wxWidgets.
Antworten
tantris
User
Beiträge: 10
Registriert: Donnerstag 31. August 2006, 10:05

Hallo,

ich würde gerne eine große, im Voraus unbekannte Menge von Daten als Grid darstellen. Dabei wäre es eigentlich aus performancegründen unabdingbar (die Daten werden eingelesen), dass nur die Daten zur Darstellung geholt werden, die tatsächlich sichtbar sind,
also z.B. wenn ich jetzt ein Textfile habe, dass ich nur die ersten 100 Zeilen hole, und erst wenn mein User so weit runterscrollt, dass er die 101. sehen könnte, werden die nächsten x Zeilen geholt.

Ich hatte eigentlich die Hoffnung, das über ein gridtable zu lösen, da das GetValue() ja schön zu implementieren ist, aber meine erste Idee, die Table dynamisch wachsen zu lassen, schlug fehl.
Kann ich das denn überhaupt, ein gridtable dynamisch wachsen lassen? Und wie bekommt das darauf definierte Grid mit, dass die Table jetzt größer ist?

Da ich aktuell noch so gut wie nichts umgesetzt habe, wäre es auch kein Problem zu sagen, dass man das komplett ohne gridtables macht, sondern direkt von Grid ableitet und mit dessen Methoden arbeitet - aber hat hier jemand eine Idee zu einem guten Konzept?
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

tantris hat geschrieben:Ich hatte eigentlich die Hoffnung, das über ein gridtable zu lösen, da das GetValue() ja schön zu implementieren ist
Hi tantris!

Das verstehe ich jetzt nicht ganz. Was funktioniert an der Variante mit ``GetValue()`` nicht?

Mein Computer ist zu schnell zum Testen. Probiert doch mal diesen Code aus:

Code: Alles auswählen

#!/usr/bin/env python -O
# -*- coding: iso-8859-1 -*-

import wx
import wx.grid
import shelve, pickle

SHELVE_FILE = "my_data.shelve"


class DataTable(wx.grid.PyGridTableBase):
    
    def __init__(self):
        wx.grid.PyGridTableBase.__init__(self)
        
        self.data = shelve.open(SHELVE_FILE, protocol = pickle.HIGHEST_PROTOCOL)
        
        if len(self.data) < 50000:
            self.add_demo_data(10000)
    
    def add_demo_data(self, count):
        print "Demodaten werden hinzugefuegt..."
        
        current_len = len(self.data)
        for i in range(current_len, len(self.data) + count):
            s = str(i)
            self.data[s] = (s, s, s, s)
            
            if i % 1000 == 0:
                print "  ", s
    
    def GetNumberRows(self):
        return len(self.data)
    
    def GetNumberCols(self):
        return 4
    
    def GetValue(self, row, col):
        return self.data[str(row)][col]
    

class MyFrame(wx.Frame):
    
    def __init__(self, parent = None, id = -1, title = "Hallo"):
        wx.Frame.__init__(self, parent, id, title)
        
        grid = wx.grid.Grid(self)
        data = DataTable()
        grid.SetTable(data, True)


def main():
    app = wx.PySimpleApp()
    frame = MyFrame()
    frame.Center()
    frame.Show()
    app.MainLoop()

if __name__ == "__main__":
    main()
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
tantris
User
Beiträge: 10
Registriert: Donnerstag 31. August 2006, 10:05

Hi Gerold,

naja mein problem ist eben, dass ich am anfang noch nicht weiß, wie groß mein Grid ist - und da es so viele Daten sind, kann ich sie nicht in Python einlesen - stell dir z.b. eine große Datei vor. Was du tust, ist im Vorfeld die Daten einlesen und dann den Kram in self.data zu stopfen - das wird bei mir nicht gehen.
Was ich brauche, ist beispielsweise eine GetValue-Methode, die dynamisch die Größe des Grids ändert, soll heißen, wenn meine Datei 2000 Zeilen hat und ich 1-100 im Speicher habe, soll das so ablaufen:
User schaut irgendwo Zeilen 1-100 an, scrollt runter. Irgendwann wäre Zeile 101 sichtbar, die gibts aber noch nicht. an dieser Stelle sollte es jetzt passieren, dass die nächsten 100 Zeilen geladen werden, so dass für den User kein Bruch da ist, sprich er kann flüssig runterscrollen.
Ich müsste also abfragen, wann die letzte Zelle, zu der Daten existieren sichtbar wird, das soll dann das einlesen von neuen Daten triggern, die Dimension des Grids muss upgedatet werden und GetValue muss Bescheid wissen... und momentan weiß ich nicht, wo ich da ansetze.

Mein erster Gehversuch sah im Wesentlichen so aus

Code: Alles auswählen

GetNumberRows(self):
    return self.numrows
und ich hatte vor, self.numrows upzudaten. Leider wird GetNumberRows aber nur bei der allerersten Grid-Erzeugung aufgerufen...
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Hi tantris!
tantris hat geschrieben:naja mein problem ist eben, dass ich am anfang noch nicht weiß, wie groß mein Grid ist - und da es so viele Daten sind, kann ich sie nicht in Python einlesen
Ändert sich die Größe während du die Daten im Grid anzeigst?
Wenn nicht, dann ändere deine Datenstruktur so um, dass du herausfinden kannst, wie viele Zeilen es gibt.

Du könntest die Daten in eine Datenbank einpflegen oder ``anydbm`` oder ``shelve`` verwenden. Es ist wichtig, dass du auf jede Datenzeile recht schnell zugreifen kannst, sonst wird dir das Grid zu langsam.

Natürlich könntest du dir auch deine Textdatei, schon beim Befüllen, so aufbereiten, dass eine Zeile immer gleich lang ist. So könntest du kurz mal an das Ende der Datei springen und du weißt wieviele Zeilen du in der Datei hast.
tantris hat geschrieben:Was du tust, ist im Vorfeld die Daten einlesen und dann den Kram in self.data zu stopfen - das wird bei mir nicht gehen.
Ich habe mir irgendwelche Demodaten beschafft. Und da ich weiß, wie schnell ``shelve`` ist und dass es diesem Objekt auch nichts ausmacht, kurz mal ein paar hundert MB an Daten zu verwalten, habe ich ``shelve`` für meine Datenstruktur verwendet. ``shelve`` hält die Daten im Dateisystem und nicht im Speicher. Deshalb kann es so große Datenmengen verwalten, ohne den Speicher zuzumüllen.
tantris hat geschrieben:dynamisch die Größe des Grids ändert
[...]
Irgendwann wäre Zeile 101 sichtbar, die gibts aber noch nicht. an dieser Stelle sollte es jetzt passieren, dass die nächsten 100 Zeilen geladen werden

Code: Alles auswählen

data = DataTable()
grid.SetTable(data)
Dieser Code veranlasst das Grid dazu, auch die Anzahl der Zeilen neu einzulesen. Allerdings widerspricht das dem gewohnten Handling. Wenn ich STRG+ENDE drücke, dann möchte ich am Ende des Grids sein. Außerdem gibt es bei mir, beim Testen, Grafikfehler bei dieser Methode. (netter Satz) Das beste und Schnellste wäre immer noch, die Daten in einem geeigneten Datenobjekt unterzubringen.

Mit wievielen Daten rechnest du denn so?

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
tantris
User
Beiträge: 10
Registriert: Donnerstag 31. August 2006, 10:05

naja am Ende kann es sein, dass Matrizen dargestellt werden, die mehrere Milliarden Zahlen beinhalten, oder aber Bäume...
ich habe eigentlich vor, das Ganze eher abstrakt anzugehen, sprich dass man ein Objekt übergibt, das gewisse Methoden hat, wie z.B. gib mir x Objekte und das entweder tut oder sagt "Sorry nix mehr da"... Ich hätte eben gerne diese Flexibilität, einfach meinem Grid nicht von Anfang an sagen zu müssen, wie groß es ist, oder wie groß es evtl. wird...
Eine andere Möglichkeit wäre natürlich, ein fixes Grid von sagen wir 100 Zeilen mal y Spalten zu nehmen, und beim Scrollen nicht das Grid zu scrollen, sondern die Daten in den Zellen zu verändern... das Grid also praktisch als eine Art Guckfenster sehen, das über die Daten geht
Antworten