20aug18: ezaggrid will not be improved further. Instead I strongly encourage to use ipyaggrid, which is more powerful and crucially allows bidirectional communication Python-JavaScript, while ezaggrid can only do Python-to-JavaScript.
To learn more check out: (1) the medium article Harnessing the power of ag-Grid in Jupyter and (2) ipyaggrid doc.
ezaggrid (meaning 'easy ag-grid') is a Python package thin wrapping the excellent ag-grid JavaScript library.
Its goal is to make it ag-grid an easy option for pandas dataframe rendering in the Jupyter notebook.
From terminal
$ pip install ezaggrid
See the demo notebooks
- demo_ezaggrid_aggregation
- demo_ezaggrid_clipboard
- demo_ezaggrid_column_definition
- demo_ezaggrid_column_filter
- demo_ezaggrid_column_groups
- demo_ezaggrid_column_headers
- demo_ezaggrid_column_resize
- demo_ezaggrid_column_row_sorting
- demo_ezaggrid_compress_data
- demo_ezaggrid_export_csv_excel
- demo_ezaggrid_pagination
- demo_ezaggrid_pivoting
- demo_ezaggrid_quickfilter
- demo_ezaggrid_several_gridoptions
- demo_ezaggrid_status_bar
- demo_ezaggrid_tool_panel
- demo_ezaggrid_multiindex_dataframe
The data must be input as a pandas DataFrame.
# data from the ag-grid documentation stored in a pandas dataframe
url = 'https://raw.githubusercontent.com/ag-grid/ag-grid-docs/master/src/olympicWinners.json'
df = pd.read_json(url)
The gridOptions must be input as a dictionary.
The only field that must not be set is rowData
as data comes from the dataframe.
For help converting a javascript gridOption object (from the official ag-grid documentation of a web example) to a Python dictionary, check out the helper_convert_gridOptions_js_to_python notebook.
# See ag-grid documentation
# https://www.ag-grid.com/javascript-grid-properties/
# example
columnDefs = [
{'headerName': "Gold", 'field': "gold", 'width': 100, 'aggFunc': 'sum', 'enableValue': True,
'allowedAggFuncs': ['sum','min','max']
},
{'headerName': "Silver", 'field': "silver", 'width': 100, 'aggFunc': 'min', 'enableValue': True},
{'headerName': "Bronze", 'field': "bronze", 'width': 100, 'aggFunc': 'max', 'enableValue': True},
{'headerName': "Total", 'field': "total", 'width': 100, 'aggFunc': 'avg', 'enableValue': True},
{'headerName': "Age", 'field': "age", 'width': 90},
{'headerName': "Country", 'field': "country", 'width': 120, 'rowGroup': True},
{'headerName': "Year", 'field': "year", 'width': 90},
{'headerName': "Date", 'field': "date", 'width': 110},
{'headerName': "Sport", 'field': "sport", 'width': 110}
]
grid_options = {
'columnDefs': columnDefs,
'groupIncludeFooter': True,
'enableSorting': True,
'showToolPanel': True,
'toolPanelSuppressPivots': True,
'toolPanelSuppressPivotMode': True,
'autoGroupColumnDef': {'headerName': "Athlete",
'field': "athlete",
'width': 200,
'cellRenderer':'agGroupCellRenderer',
'cellRendererParams': {
'footerValueGetter': '"Total (" + x + ")"',
'padding': 5
}
}
}
To display a the data as as ag-grid
# create object
ag = AgGrid(# dataframe or list of dict of data items
grid_data=df_data,
# dictionary of gridOptions - from ag-grid documentation
grid_options=grid_options,
# list of tuples (name, gridOptions) - dropdown menu to select from
# NOTE: grid_options xor grid_options_multi must be set
grid_options_multi=[('name A', grid_options_A), ('name B', grid_options_B)],
# add css rules as a string - default=None
css_rules=None,
# width of containter in px
width=850,
# height of containter in px
height=500,
# quick filter text box boolean - default=False
quick_filter=False,
# export csv button boolean - default=False
export_csv=False,
# export excel button boolean - default=False
export_excel=False,
# automatic column definitions from dataframe - default=False
implicit_col_defs=False,
# add index to data - default=True
index=True,
# In case of multiindex dataframe and therefore
# row and col grouping, display row index as columns
# default=False
keep_multiindex=False,
# ag-grid theme - default='ag-theme-fresh'
theme='ag-theme-fresh',
# ag-grid license necessary for enterprise features - default=None
# must be stored in ~/.ag_grid_license
license=get_license(),
# iframe boolean to encapsulate js in iframe - default=False
iframe=False,
# hide_grid boolean to hide grid - default=False - may be useful to only show export buttons
hide_grid=False,
# compress_data boolean to gunzip then convert to base64 json data - default=False
compress_data=False,
)
# display
ag.show()
If grid_data is a dataframe, the column types are automatically detected.
The following types are associated an ag-grid column type to allow for correct sorting and filtering:
- numbers, int and floats
- dates
- boolean
- text
This automatic customization is done through the ag-grid gridOptions property columnDefs
.
Note: If a dataframe column contains a dot ('.') it will be automatically converted to an underscore ('_') and a warning message is displayed. Because dots in field
are not supported in ag-grid.
If a multiindex dataframe is passed as argument, a specific treatment takes place so that a similar diplay is rendered by ag-grid using row and column grouping.
See the demo_ezaggrid_multiindex_dataframe demo notebook.
Both the grid_data
and grid_options
, or grid_options_multi
, may be slightly modified upon AgGrid instance creation. To get back their transformed value:
# export grid_data
updated_grid_data = ag.export_data()
# export grid_options
updated_grid_options = ag.export_options()
# export grid_options_multi
updated_grid_options = ag.export_options_multi()
You might need it to tamper the options further.
This package is not a Jupyter widget. So the displayed ag-grid is ready only ie. no modification of the ag-grid will be visible from the Python kernel. In other words ezaggrid is a readonly package.
As a consequence for example the Cell Editing feature is only interesting if you want to modify the data and then immediately save it as an Excel or CSV file with the corresponding Excel Export and CSV Export features.
The ag-grid features available in demo notebook ie. tested are in bold characters:
- Column Definitions
- Column Groups
- Column Headers
- Column Resizing
- Column Moving
- Column Filter
- Quick Filter
- External Filter
- Row Sorting
- Row Dragging
- Row Selection
- Range Selectione
- Grid Size
- Column Spanning
- Column Pinning
- Row Pinning
- Row Height
- Cell Styles
- Row Styles
- Value Handlers
- Cell Rendering
- Cell Editing
- Keyboard Navigation
- Touch Support
- Animation
- Accessing Data
- Pagination
- Updating Data
- View Refresh
- Change Detection
- Internationalisation
- Performance
- Accessibility
- Full Width Rows
- Master / Detaile
- Aligned Grids
- CSV Export
- Excel Export
- RTL
- Custom Icons
- Overlays
- Layout For Print
- Row Grouping
- Tree Data
- Aggregation
- Pivoting
- Tool Panel
- Clipboard
- Column Menu
- Context Menu
- Status Bar
- License Key
Why the iframe
option ?
-
To make the package compatible with JupyterLab which disables javascript injection.
-
Note that even in the classical notebook there is no downside in using the iframe option - except possibly a bit more tampering with the iframe dimensions.
- Test iframe feature.