arturdeluca
arturdeluca

Reputation: 53

Return DataFrame using ipywidgets Button

I'm currently creating a Class that inherits a DataFrame from pandas. I'm interested in developing a method called 'new_filter' that is a fancier execution of a DataFrame command:

import pandas as pd
from ipywidgets import widgets
from IPython.display import display
import numpy as np

class Result(pd.DataFrame):

@property
def _constructor(self):
    return Result

def _filter_done(self, c):
    self._column_name = self._filter_dd.value
    self._expression = self._filter_txt.value
    return self[eval('self.'+ self._column_name +'  '+self._expression)]

def new_filter(self):
    self._filter_dd = widgets.Dropdown(options=list(self.columns),
                                            description='Column:')
    self._filter_txt = widgets.Text(description='Expr:')
    self._filter_button = widgets.Button(description = 'Done')
    self._filter_box = widgets.VBox([self._filter_dd, self._filter_txt, self._filter_button])
    display(self._filter_box)
    self._filter_button.on_click(self._filter_done)

After creating an object like:

test = Result(np.random.randn(3,4), columns=['A','B','C','D']) #just an example
test_2 = test.new_filter()

Then, for example: Widget Output

What I want is that 'test_2' be an object from 'Result' class. Is there any solution to this?

Upvotes: 2

Views: 2308

Answers (1)

ssunkara
ssunkara

Reputation: 91

First, you will have to return something in the function new_filter. Second, if you want the same object to be modified, it is a bit hard I think. One thing you can do is to have an object which has a trait which can be updated in _filter_done.

Here is a small example of how you can do it:

import pandas as pd
from ipywidgets import widgets
from IPython.display import display
import numpy as np

class Result(pd.DataFrame):
    @property
    def _constructor(self):
        return Result

    def _filter_done(self, obj, c):
        ## obj is the obejct to be modified. 
        ## Updating its data attribute to have the filtered data.
        self._column_name = self._filter_dd.value
        self._expression = self._filter_txt.value
        obj.data = self[eval('self.'+ self._column_name +'  '+self._expression)]

    def new_filter(self):
        self._filter_dd = widgets.Dropdown(options=list(self.columns),
                                            description='Column:')
        self._filter_txt = widgets.Text(description='Expr:')
        self._filter_button = widgets.Button(description = 'Done')
        self._filter_box = widgets.VBox([self._filter_dd, self._filter_txt, self._filter_button])
        display(self._filter_box)

        result_obj = FilterResult()
        self._filter_button.on_click(lambda arg: self._filter_done(result_obj, arg))
        return result_obj

from traitlets import HasTraits
from traittypes import DataFrame

class FilterResult(HasTraits):
    data = DataFrame()

With the same example code as in your question, i.e.,

test = Result(np.random.randn(3,4), columns=['A', 'B', 'C','D']) #just an example
test_2 = test.new_filter()

You can see that whenever you click on done, the updated dataframe is in test_2.data.

Upvotes: 2

Related Questions