Highlight word in DT in shiny based on regex

偶尔善良 提交于 2019-12-10 14:06:17

问题


Using DT in shiny, I want to be able to highlight the selected word. Setting searchHighlight = TRUE is close to what I want, but this will also highlight words that include the search. For example, if I am searching for "on" it will also match "stone", highlighting the "on" in the middle.

EXAMPLE IMAGE:

I can refine the search options so regex = TRUE, but then no highlighting occurs. This is also true if I want to use regex like "on|in", for example.

EXAMPLE (including regex):

library(shiny)
library(DT)
library(data.table)

example_data <- data.table(words = c("on", "scone", "wrong", "stone"), 
                           description = c("The word on", "Scone is not on.", "Not on either", "Not here at all"))

ui = shinyUI(fluidPage(

  sidebarLayout(
    sidebarPanel(
      textInput("word_select", label = "Word to search")
      ),
    mainPanel(
      dataTableOutput("word_searched")
    )
  )
))

server = shinyServer(function(input, output, session) {

  output$word_searched <- renderDataTable({
    datatable(
      example_data, 
      options = list(searchHighlight = TRUE, 
                     search = list(regex = TRUE, 
                                   search = paste0("\\b", tolower(input$word_select), "\\b")))
    )
  })

  })

shinyApp(ui = ui, server = server)

The DT is already being filtered on the word by a reactive expression, so all the fields will definitely include the selected word, but I just want to avoid confusion from users thinking that longer words are being included in the search erroneously. I haven't done this in the example but just confirming this is not the element I'm concerned about.

Thanks for your help.

(EDITED to add an example of a word with punctuation in the example data.)


回答1:


Instead of relying on datatable's search functionality you can create a reactive element that first filters by the input, and then replaces the matching words with the same word embedded in a <span style="background-color:yellow;"> tag. This should allow more search flexibility via more complex regex.

You'll need to add escape = F to datatable so the HTML tag is interpreted properly. I've added options = list(dom = "lt") to datatable to remove the datatable's search field and direct attention to the left search field.

The filtering criteria are left fairly fuzzy to keep the table from disappearing until a perfect match is found – i.e. the table shouldn't disappear when you type "o" because there's no perfect match, and then reappear at "on". The highlights then only appear if a matching word is found, i.e. on, On, and on., but not stone, scone, etc. Here's a glimpse of what it looks like:

And here's the code. Note that I use dplyr's filtering and mutating functions because they can easily be applied to multiple columns via their *_all variants:

library(shiny)
library(DT)
library(data.table)
library(dplyr) # For `filter_all` and `mutate_all`.

example_data <- iris
    # data.table(words = c("on", "scone", "wrong", "stone"), 
    #                        description = c("The word on", "Scone is not on.", "Not on either", "Not here at all"))

ui = shinyUI(fluidPage(

    sidebarLayout(
        sidebarPanel(
            textInput("word_select", label = "Word to search")
        ),
        mainPanel(
            dataTableOutput("word_searched")
        )
    )
))

server = shinyServer(function(input, output, session) {

    # This is your reactive element.
    df_reactive <- reactive({
            example_data %>%
                # Filter if input is anywhere, even in other words.
                filter_all(any_vars(grepl(input$word_select, ., T, T))) %>% 
                # Replace complete words with same in HTML.
                mutate_all(~ gsub(
                              paste(c("\\b(", input$word_select, ")\\b"), collapse = ""),
                              "<span style='background-color:yellow;'>\\1</span>",
                              .,
                              TRUE,
                              TRUE
                              )
                          )
    })

    # Render your reactive element here.
    output$word_searched <- renderDataTable({
        datatable(df_reactive(), escape = F, options = list(dom = "lt"))
    })

})

shinyApp(ui = ui, server = server)



回答2:


I'm not sure this is what you exactly want but this is close I think: this does not perform an exact search (e.g. "on" will match "stone") but this only highlights the exact match (e.g. "on" will not be highlighted). This uses the mark.js library.

dtable <- datatable(iris[c(1,2,51,52,101,102),], 
                    options = list(
                      mark = list(accuracy = "exactly")
                    )
)
dep1 <- htmltools::htmlDependency(
  "datatables.mark", "2.0.1", 
  src = c(href = "https://cdn.datatables.net/plug-ins/1.10.19/features/mark.js"),
  script = "datatables.mark.min.js")
dep2 <- htmltools::htmlDependency(
  "jquery.mark", "8.11.1", 
  src = c(href = "https://cdnjs.cloudflare.com/ajax/libs/mark.js/8.11.1"), 
  script = "jquery.mark.min.js")
dtable$dependencies <- c(dtable$dependencies, list(dep1, dep2))
dtable



来源:https://stackoverflow.com/questions/56633621/highlight-word-in-dt-in-shiny-based-on-regex

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!