qgrid

quantopian/qgrid

Uses mleibman/SlickGrid. Examples for slickgrid: Examples · mleibman/SlickGrid Wiki

Alt fork for slickgrid: 6pac/SlickGrid (useful since slickgrid is not being updated right now.)

How to install?

pip install git+https://github.com/quantopian/qgrid

In [1]:
import warnings
warnings.filterwarnings('ignore')

In [2]:
NEED_TO_INSTALL = True

import qgrid

if NEED_TO_INSTALL:
    qgrid.nbinstall(overwrite=True)  # copies javascript dependencies to your /nbextensions folder 
    qgrid.set_defaults(remote_js=False, precision=4)

In [3]:
# https://github.com/quantopian/qgrid/pull/49#issue-121942807

import qgrid
from ipywidgets import widgets
from ipywidgets.widgets import Button, VBox
from IPython.display import display
import pandas as pd
from pandas import DataFrame

pd.set_option('display.max_rows', 8)

from pandas.io.data import get_data_yahoo
spy = get_data_yahoo(
    symbols='SPY',
    start=pd.Timestamp('2011-01-01'),
    end=pd.Timestamp('2014-01-01'),
    adjust_price=True,
)
# use an integer index so we can add rows
spy = spy.reset_index()

qgrid.nbinstall(overwrite=True)
grid = qgrid.QGridWidget(df=spy)
button = Button(description='Update')

status = widgets.Text(
    background='red'
)


def update(button):
    new = get_data_yahoo(
        symbols='SPY',
        start=pd.Timestamp('2011-01-01'),
        end=pd.Timestamp('2014-01-01'),
        adjust_price=True,
    )
    grid.df = new
button.on_click(update)

def selection_change(widget, changes, *args, **kwargs):
    print (widget, changes, args, kwargs)
    #print (changes)
    if changes.get('type') == 'selection_change':
        print ('selection_change', changes.get('rows'), widget.get_selected_rows())
        status.value = unicode(widget.get_selected_rows())
    elif changes.get('type') == 'cell_change':
        print ('cell_change', changes)
        


grid.on_msg(selection_change)

display(VBox((button, status, grid)))


(<qgrid.grid.QGridWidget object at 0x106f6f710>, {'items': [{'Index': 0, 'High': 115.1731, 'Adj_Ratio': 0.9026, 'slick_grid_id': 'row0', 'Volume': 138725200, 'Low': 113.4581, 'Date': '2011-01-03T00:00:00.000Z', 'Close': 114.6767, 'include': True, 'Open': 114.3698, 'excluded_by': {}}], 'rows': [0], 'type': 'selection_change', 'indexes': [0]}, ([],), {})
('selection_change', [0], [0])
(<qgrid.grid.QGridWidget object at 0x106f6f710>, {'items': [{'Index': 1, 'High': 114.9655, 'Adj_Ratio': 0.9026, 'slick_grid_id': 'row1', 'Volume': 137409700, 'Low': 113.9004, 'Date': '2011-01-04T00:00:00.000Z', 'Close': 114.6135, 'include': True, 'Open': 114.9294, 'excluded_by': {}}, {'Index': 0, 'High': 115.1731, 'Adj_Ratio': 0.9026, 'slick_grid_id': 'row0', 'Volume': 138725200, 'Low': 113.4581, 'Date': '2011-01-03T00:00:00.000Z', 'Close': 114.6767, 'include': True, 'Open': 114.3698, 'excluded_by': {}}], 'rows': [1, 0], 'type': 'selection_change', 'indexes': [1, 0]}, ([],), {})
('selection_change', [1, 0], [1, 0])
(<qgrid.grid.QGridWidget object at 0x106f6f710>, {'items': [{'Index': 159, 'High': 105.5697, 'Adj_Ratio': 0.911, 'slick_grid_id': 'row159', 'Volume': 428281300, 'Low': 102.4904, 'Date': '2011-08-19T00:00:00.000Z', 'Close': 102.618, 'include': True, 'Open': 102.9095, 'excluded_by': {}}], 'rows': [2], 'type': 'selection_change', 'indexes': [159]}, ([],), {})
('selection_change', [2], [2])
(<qgrid.grid.QGridWidget object at 0x106f6f710>, {'items': [{'Index': 189, 'High': 104.3485, 'Adj_Ratio': 0.9157, 'slick_grid_id': 'row189', 'Volume': 365136800, 'Low': 100.5573, 'Date': '2011-10-03T00:00:00.000Z', 'Close': 100.6672, 'include': True, 'Open': 103.0115, 'excluded_by': {}}, {'Index': 159, 'High': 105.5697, 'Adj_Ratio': 0.911, 'slick_grid_id': 'row159', 'Volume': 428281300, 'Low': 102.4904, 'Date': '2011-08-19T00:00:00.000Z', 'Close': 102.618, 'include': True, 'Open': 102.9095, 'excluded_by': {}}], 'rows': [3, 2], 'type': 'selection_change', 'indexes': [189, 159]}, ([],), {})
('selection_change', [3, 2], [3, 2])
(<qgrid.grid.QGridWidget object at 0x106f6f710>, {'items': [{'Index': 190, 'High': 103.0939, 'Adj_Ratio': 0.9157, 'slick_grid_id': 'row190', 'Volume': 459177500, 'Low': 98.3779, 'Date': '2011-10-04T00:00:00.000Z', 'Close': 102.8741, 'include': True, 'Open': 99.2204, 'excluded_by': {}}], 'rows': [0], 'type': 'selection_change', 'indexes': [190]}, ([],), {})
('selection_change', [0], [0])

what I'm learning about qgrid

some events coming from qgrid:

What to do next:

  • attach my own event handler to the various events available on QGridWidget.

What can we do with qgrid?

  • pick up on row selection changes
  • pick up on cell changes
  • add row
  • delete rows

Toy example to exercise all the functionality of qgrid


In [ ]:
columns = ['id', 'name','color','marbles']

data = [

    {'id':0, 'name': 'Fred', 'color':'red', 'marbles':2},
    {'id':1, 'name': 'Zhang', 'color':'blue', 'marbles':5},
    {'id':2, 'name': 'Deb', 'color':'orange', 'marbles':0}
]

df = DataFrame(data, columns=columns)
df

In [ ]:
df.loc[10] = {'id':2, 'name': 'Kim', 'color':'orange', 'marbles':0}
df

In [ ]:
df.index

In [ ]:
data_widget = qgrid.QGridWidget(df=df, remote_js=False)

add_row = widgets.Button(description="Add Row")
add_row.on_click(data_widget.add_row)

rem_row = widgets.Button(description="Remove Row")
rem_row.on_click(data_widget.remove_row)


display(widgets.HBox((add_row, rem_row)), data_widget)

In [ ]:
df.columns

In [ ]:
df

In [ ]:
len(df)

In [ ]:
# replace df if we need ...
data_widget.df = df
data_widget._df_changed()

In [ ]:
data_widget

Extending widgets to get at more events?


In [ ]:
w = widgets.Text()

def text_event(widget, changes, *args, **kwargs):
    print (widget, changes, args, kwargs)
    print (changes)


w.on_msg(text_event)

display(w)

How does the msg framework work?

  • how do messages go from JS to Python?

  • message from Python to JS?


In [ ]:
# thought this would be interesting but I think the only event supported is submit.

class MyText(widgets.Text):
    def _handle_string_msg(self, _, content, buffers):
        """Handle a msg from the front-end.
        Parameters
        ----------
        content: dict
            Content of the msg."""
            
        super(MyText, self)._handle_string_msg( _, content, buffers)
        
        print (_, content, buffers)
        
        
w = MyText()
w

Appendix: Clearing widgets


In [ ]:
assert False

In [ ]:
%%javascript

$('div.widget-area button.close:visible').click();

In [ ]: