PyGridTableBase

Tom B <[email protected]>
Newsgroups gmane.comp.python.wxpython.devel
Message-ID <[email protected]>
Posted this to the user forum but now think a wxpython developer might have 
better insight as there were zero replies, but lots of views..

Does anyone know of examples where gridlib.PyGridTableBase is specialized
to wrap a pandas dataframe object.  The dataframe brings in a lot of 
functionality, such as sorting.  I've taken several examples and modified 
to use a wrapped
dataframe, but the sort never works.  The dataframe does get sorted but the 
grid display is never updated.
Attached is an example where the CVSData source works (commented out), and 
while PandasDataSource
sorts the dataframe, the display not updated.     

The CVXData version represents the table as a list of lists. Somewhere in 
the class structure there is an assumption that the table has to be a [[]], 
and not column data, even though you can override API's for accessing 
elements of the table?.  Or could it be I'm not overriding the needed 
functions ?

Any insights are appreciated

-- 
You received this message because you are subscribed to the Google Groups "wxPython-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
For more options, visit https://groups.google.com/d/optout.
sample_data.csv (text/csv, 427 B)
User ID,First Name,Last Name,Address,Phone Number,Can Call
U123,Joe,Cobra,384 Knoll Street,555-555-7878,True
U321,Sally,Smith,567 Kerber Lane,555-555-9293,True
U728,Fred,Flinstone,3 Bedrock Lane,555-555-0001,True
U134,Mary,Williams,4739 Prairie Drive,555-555-0103,True
U128,Ken,Keller,574 1st Street,555-555-8888,False
U689,Yuki,Morimoto,8394 Sunset Blvd,555-555-9873,True
U991,Craig,Johnson,167 Beach Drive,555-555-7877,False
dataGrid.py (text/x-python, 5.8 KB)
# Chapter 5: Data Displays and Grids
# Recipe 4: Getting started with the data grid
#
import csv
from io import StringIO
import wx
import wx.grid as gridlib
import pandas as pd

class CSVDataSource(gridlib.PyGridTableBase):
    def __init__(self):
        super(CSVDataSource, self).__init__()
        self._data = None
        self._header = None
        self._readOnly = list()
        
        self._roAttr = gridlib.GridCellAttr()
        self._roAttr.SetReadOnly()
        c = wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT)
        self._roAttr.TextColour = c

    def LoadFile(self, fileName):
        reader = csv.reader(open(fileName, 'r'))
        self._data = [row for row in reader]
        self._header = self._data.pop(0)
        self._readOnly = list()

    def GetData(self):
        if not self._data:
            return ""

        buff = StringIO()
        writer = csv.writer(buff)
        writer.writerow(self._header)
        writer.writerows(self._data)
        return buff.getvalue()

    def SetColReadOnly(self, col):
        self._readOnly.append(col)

    def GetAttr(self, row, col, kind):
        if col in self._readOnly:
            self._roAttr.IncRef()
            return self._roAttr
        return None

    def Sort(self, col, ascending):
        #self._data.sort(None, lambda data: data[col], not ascending)
        self._data.sort()

    def GetNumberRows(self):
        return len(self._data) if self._data else 0

    def GetNumberCols(self):
        return len(self._header) if self._header else 0

    def GetValue(self, row, col):
        if not self._data:
            return ""
        else:
            return self._data[row][col]

    def SetValue(self, row, col, value):
        if self._data:
            self._data[row][col] = value

    def GetColLabelValue(self, col):
        return self._header[col] if self._header else None

class PandasDataSource(gridlib.PyGridTableBase):
    def __init__(self):
        super(PandasDataSource, self).__init__()
        self._data = None
        self._header = None
        self._readOnly = list()
        
        self._roAttr = gridlib.GridCellAttr()
        self._roAttr.SetReadOnly()
        c = wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT)
        self._roAttr.TextColour = c

    def LoadFile(self, fileName):
        self._data = pd.read_csv(fileName)
        self._header = self._data.columns.tolist()
        self._readOnly = list()

    def GetData(self):
        if self._data is None:
            return ""

        buff = StringIO()
        writer = csv.writer(buff)
        writer.writerow(self._header)
        writer.writerows(self._data)
        return buff.getvalue()

    def SetColReadOnly(self, col):
        self._readOnly.append(col)

    def GetAttr(self, row, col, kind):
        if col in self._readOnly:
            self._roAttr.IncRef()
            return self._roAttr
        return None

    def Sort(self, col, ascending):
        #self._data.sort(None, lambda data: data[col], not ascending)
        #xx.sort_values(by=[self.colnames[col]],inplace=True)
        self._data.sort_values(by=[self._header[col]],inplace=True)

    def GetNumberRows(self):
        if self._data is None:
            return 0
        return len(self._data) 

    def GetNumberCols(self):
        if self._header is None:
            return 0
        return len(self._header)  

    def GetValue(self, row, col):
        if self._data is None:
            return ""
        else:
            return self._data.get_value(row,self._header[col])

    def SetValue(self, row, col, value):
        if not self._data is None:
            self._data.set_value(row,self._header[col], value)

    def GetColLabelValue(self, col):
        return self._header[col] if self._header else None

class CSVEditorGrid(gridlib.Grid):
    def __init__(self, parent):
        super(CSVEditorGrid, self).__init__(parent)

        #self._data = CSVDataSource()
        self._data = PandasDataSource()
        self.SetTable(self._data)

        self.Bind(gridlib.EVT_GRID_COL_SORT, self.OnSort)

    def OnSort(self, event):
        self._data.Sort(event.Col,
                        self.IsSortOrderAscending())

    def LoadFile(self, fileName):
        self._data.LoadFile(fileName)
        self.SetTable(self._data)
        self.AutoSizeColumns()

    def SaveFile(self, fileName):
        with open(fileName, 'w') as fileObj:
            fileObj.write(self._data.GetData())

    def SetColReadOnly(self, col):
        self._data.SetColReadOnly(col)

#------- Sample Application ---------#

class MyFrame(wx.Frame):
    def __init__(self, parent, title):
        super(MyFrame, self).__init__(parent, title=title)

        menub = wx.MenuBar()
        fmenu = wx.Menu()
        fmenu.Append(wx.ID_OPEN)
        fmenu.Append(wx.ID_SAVE)
        menub.Append(fmenu, "File")
        self.SetMenuBar(menub)
        self.CreateStatusBar()

        sizer = wx.BoxSizer()
        self._file = 'sample_data.csv'
        self._grid = CSVEditorGrid(self)
        self._grid.LoadFile(self._file)
        self._grid.SetColReadOnly(0)
        
        sizer.Add(self._grid, 1, wx.EXPAND)
        self.SetSizer(sizer)
        self.SetInitialSize()
        
        self.Bind(wx.EVT_MENU, self.OnSave, id=wx.ID_SAVE)
        self.Bind(wx.EVT_MENU, self.OnOpen, id=wx.ID_OPEN)

    def OnOpen(self, event):
        dlg = wx.FileDialog(self, "Open CSV File", wildcard="*.csv")
        result = dlg.ShowModal()
        if result == wx.ID_OK:
            self._grid.LoadFile(dlg.Path)
        dlg.Destroy()

    def OnSave(self, event):
        self._grid.SaveFile(self._file)
        self.SetStatusText("Saved file: %s" % self._file)

class MyApp(wx.App):
    def OnInit(self):
        self.frame = MyFrame(None, title="Data Grid")
        self.frame.Show();
        return True

if __name__ == "__main__":
    app = MyApp(False)
    app.MainLoop()
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.