data =FileAttachment("palmer-penguins.csv").csv({ typed:true })filtered = data.filter(penguin => {return penguin.bill_length> billLengthMin && islands.includes(penguin.island)})// Update table data when filtered data changesReactable.setData('tbl', filtered)
Using reactable to filter Observable charts
// Create an Observable value that automatically tracks the table's filtered datafilteredData = Generators.observe(change => {return Reactable.onStateChange('tbl-input', state => {change(state.sortedData) })})
---title: "Using Observable with reactable in Quarto"format: html: echo: false code-tools: true---Examples of using Observable with reactable in Quarto, based on the [Observable JS Penguins example](https://quarto.org/docs/interactive/ojs/examples/penguins.html)from the Quarto documentation.:::{.callout-note}This is a work in progress, and requires new features in reactable v0.4.0.:::Source code: [observable-reactable.qmd](https://github.com/glin/reactable/blob/main/vignettes/quarto/observable-reactable.qmd)## Using Observable Inputs to filter reactable```{ojs}//| panel: inputviewof billLengthMin = Inputs.range( [32,50], { value:35,step:1,label:"Bill length (min):" })viewof islands = Inputs.checkbox( ["Torgersen","Biscoe","Dream"], { value: ["Torgersen","Biscoe"],label:"Islands:" })``````{ojs}//| include: falsedata =FileAttachment("palmer-penguins.csv").csv({ typed:true })filtered = data.filter(penguin => {return penguin.bill_length> billLengthMin && islands.includes(penguin.island)})// Update table data when filtered data changesReactable.setData('tbl', filtered)``````{r}library(reactable)data <- read.csv("palmer-penguins.csv")reactable( data, wrap = FALSE, resizable = TRUE, minRows =10, elementId ="tbl")```## Using reactable to filter Observable charts```{ojs}// Create an Observable value that automatically tracks the table's filtered datafilteredData = Generators.observe(change => {return Reactable.onStateChange('tbl-input', state => {change(state.sortedData) })})``````{r}library(reactable)library(htmltools)data <- read.csv("palmer-penguins.csv")# Select input filter with an "All"default optionselectFilter <-function(tableId, style ="width: 100%; height: 100%;") {function(values, name) {tags$select( # Set to undefined to clear the filter onchange =sprintf("const value =event.target.value Reactable.setFilter('%s','%s', value ==='__ALL__'?undefined: value)", tableId, name), # "All" has a special value to clear the filter, and is the default optiontags$option(value ="__ALL__","All"),lapply(unique(values), tags$option),"aria-label"=sprintf("Filter %s", name), style = style ) }}# Min range filter input that handles NaNsminRangeFilter <-function(tableId, style ="width: 100%;") {function(values, name) { values <- na.omit(values) oninput <-sprintf("Reactable.setFilter('%s', '%s', this.value)", tableId, name)tags$input( type ="range", min =floor(min(values)), max =ceiling(max(values)), value =floor(min(values)), oninput = oninput, style = style,"aria-label"=sprintf("Filter by minimum %s", name) ) }}# Min value filter method that handles NaNsfilterMinValue <-JS("(rows, columnId, filterValue) => {return rows.filter(row => {const value = row.values[columnId]return!isNaN(value) && value >= filterValue })}")reactable( data, columns =list( species =colDef( filterInput =selectFilter("tbl-input") ), island =colDef( filterInput =selectFilter("tbl-input") ), bill_length =colDef( filterMethod = filterMinValue, filterInput =minRangeFilter("tbl-input") ), sex =colDef( filterInput =selectFilter("tbl-input"), # Exact match filter method filterMethod =JS("(rows, columnId, filterValue) => {return rows.filter(row => row.values[columnId] === filterValue) }") ) ), filterable = TRUE, wrap = FALSE, resizable = TRUE, defaultPageSize =5, minRows =5, elementId ="tbl-input")```### Penguin body mass by sex and species```{ojs}Plot.rectY(filteredData, Plot.binX( { y:"count" }, { x:"body_mass",fill:"species",thresholds:20 } )).plot({facet: {data: filteredData,x:"sex",y:"species",marginRight:80 },marks: [ Plot.frame(), ] })```