tonycpsu/panwid

Display Pandas DataFrame

white-gecko opened this issue · 4 comments

Is it possible to provide a pandas DataFrame? This should have the same structure as what the DataTable expects but somehow I don't have success.

data_table = DataTable(
    columns = [
        DataTableColumn("path"),
        DataTableColumn("count"),
    ],
    data=DataFrame(data=[["/", 1],["/home", 2],["/tmp",3]], columns=["path", "count"]),
    cell_selection=True,
    with_scrollbar=True,
)

But I get:

TypeError: 'str' object does not support item assignment

So far I'm doing some uncoordinated hacking, If this is a dump issue, just close it uncommented.

One problem there is that the DataFrame name from Pandas collides with the one from panwid. Most people import Pandas as pd and then use pd.DataFrame.

I originally tried using Pandas as the underlying data structure for the table contents, but found that raccoon was a better fit for most of my use cases at the time. Pandas has changed a lot since then, so maybe it's worth investigating again or at least giving users the option of which to use, but I think the only way to do it now would be to use df.iterrows().

A wrapper class like this is probably the best way to go for now:

#!/usr/bin/env python3

import urwid
from panwid.datatable import *
import numpy as np
import pandas as pd


def unhandled_input(key):
    if key in ("q", "Q"):
        raise urwid.ExitMainLoop()

class PandasDataTable(DataTable):

    def __init__(self, pdf, *args, **kwargs):

        self.pdf = pdf
        super().__init__(*args, **kwargs)

    @property
    def columns(self):
        return [
            DataTableColumn(c)
            for c in self.pdf.columns
        ]

    def query(self, *args, **kwargs):
        for i, row in self.pdf.iterrows():
            yield row


def main():

    pdf = pd.DataFrame(
        np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]),
        columns=['a', 'b', 'c']
    )

    data_table = PandasDataTable(pdf)

    loop = urwid.MainLoop(
        urwid.Frame(data_table),
        unhandled_input=unhandled_input
    )
    loop.run()


if __name__ == "__main__":
    main()

...which I just realized only works with recent changes I've made to the unstable branch, which I just pushed a moment ago.

I'm on the unstable branch anyways ;-) Thank you!