Skip to content

Instantly share code, notes, and snippets.

@etrotta
Created July 30, 2024 23:28
Show Gist options
  • Select an option

  • Save etrotta/942680cd7fd222bfcf58f3f86b3d2802 to your computer and use it in GitHub Desktop.

Select an option

Save etrotta/942680cd7fd222bfcf58f3f86b3d2802 to your computer and use it in GitHub Desktop.
FastHTML + Polars Testing

Brief testing using fasthtml + polars + ag-grid

The way I'm injecting parameters into JS via string templates is definitely a terrible idea, this is just to show it is possible. I don't like frontend/JS whatsoever and don't plan to turn this into a proper plugin/component.

  • -eager files: Load the entire data in one go
  • main.py and table.js: Lazily load chunks as you scroll

The data files I used for testing are not included, it should work pretty much 'plug-n-play' with any CSV or Parquet file you have laying around.

from fasthtml import FastHTML, picolink
from fasthtml.common import *
import polars as pl
import uvicorn
import string
app = FastHTML(
hdrs=(
picolink,
Script(src="https://cdn.jsdelivr.net/npm/ag-grid-community/dist/ag-grid-community.min.js"),
),
live=True
)
template = string.Template(open('table-eager.js').read())
df = pl.read_csv('iris.csv')
def create_grid(id: str, df: pl.DataFrame) -> Div:
fields = [ {"field": column} for column in df.columns ]
data = df.write_json()
return Div(
H2(f"Test Grid ID: {id}", style="padding-left: 5%;"),
Div(id=id, cls="ag-theme-quartz", style="height: 500px; width: 80%; padding-left: 5%;"),
Script(template.substitute(DATA=data, COLUMNS=fields, DIV_ID=id)),
)
@app.get("/")
def home():
grid = create_grid('polars', df)
return Title("Polars Grid"), grid
if __name__ == '__main__':
uvicorn.run("main:app", host='0.0.0.0', port=8000, reload=True)
from fasthtml import FastHTML, picolink
from fasthtml.common import *
import polars as pl
import polars.selectors as cs
import uvicorn
import string
app = FastHTML(
hdrs=(
picolink,
Script(src="https://cdn.jsdelivr.net/npm/ag-grid-community/dist/ag-grid-community.min.js"),
),
live=True
)
template = string.Template(open('table.js').read())
df = pl.scan_parquet('data.parquet')
def create_grid(id: str, df: pl.DataFrame) -> Div:
fields = [ {"field": column} for column in df.collect_schema().names() ]
return Div(
H2(f"Test Grid ID: {id}", style="padding-left: 5%;"),
Div(id=id, cls="ag-theme-quartz", style="height: 500px; width: 80%; padding-left: 5%;"),
Script(template.substitute(COLUMNS=fields, DIV_ID=id)),
)
@app.get("/")
def home():
grid = create_grid('polars', df)
return Title("Polars Grid"), grid
@app.get("/data")
def get_data(dataset: str, startRow: int, endRow: int):
data = df.with_row_index('_idx').slice(startRow, endRow-startRow).collect()
json = data.select(cs.exclude('_idx')).to_dicts()
last_row = data.select(pl.col('_idx').tail(1)).item()
return {"data": json, "last_row": (startRow + len(json)) if len(json) < (endRow - startRow) else None}
if __name__ == '__main__':
uvicorn.run("main:app", host='0.0.0.0', port=8000, reload=True)
// Grid Options: Contains all of the Data Grid configurations
const gridOptions = {
// Row Data: The data to be displayed.
rowData: $DATA,
// Column Definitions: Defines the columns to be displayed.
columnDefs: $COLUMNS
};
// Your Javascript code to create the Data Grid
const myGridElement = document.querySelector('#$DIV_ID');
agGrid.createGrid(myGridElement, gridOptions);
function getRows(params){
return fetch(`/data?startRow=$${params.startRow}&endRow=$${params.endRow}&dataset=$DIV_ID`)
.then(async (data) => {
const body = await data.json();
params.successCallback(body.data, body.last_row);
});
}
const myDataSource = {
getRows: getRows,
};
// Grid Options: Contains all of the Data Grid configurations
const gridOptions = {
// Column Definitions: Defines the columns to be displayed.
columnDefs: $COLUMNS,
rowModelType: 'infinite',
datasource: myDataSource
};
// Your Javascript code to create the Data Grid
const myGridElement = document.querySelector('#$DIV_ID');
agGrid.createGrid(myGridElement, gridOptions);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment