selectors: Pattern-Matching Callback Selectors

selectorsR Documentation

Pattern-Matching Callback Selectors

Description

Symbols which reference pattern-matching callback selectors with the same names

Usage

ALL

ALLSMALLER

MATCH

Format

An object of class name of length 1.

An object of class name of length 1.

An object of class name of length 1.

Details

ALL, ALLSMALLER and MATCH are symbols corresponding to the pattern-matching callback selectors with the same names. These allow you to write callbacks that respond to or update an arbitrary or dynamic number of components. Because they are symbols (see name) rather than functions, each has no arguments. For more information, see the callback section in Dash.

For pattern-matching callbacks, the id field of a component is written in JSON-like syntax. The resulting id is then transformed into a dictionary object when serialized for use by the Dash renderer within the web browser. The fields are arbitrary keys, which describe the targets of the callback.

For example, when we write input(id=list("foo" = ALL, "bar" = "dropdown"), Dash interprets this as "match any input that has an ID list where 'foo' is 'ALL' and 'bar' is anything." If any of the dropdown value properties change, all of their values are returned to the callback.

However, for readability, we recommend using keys like type, index, or id. type can be used to refer to the class or set of dynamic components and index or id could be used to refer to the component you are matching within that set. While your application may have a single set of dynamic components, it's possible to specify multiple sets of dynamic components in more complex apps or if you are using MATCH.

Like ALL, MATCH will fire the callback when any of the component's properties change. However, instead of passing all of the values into the callback, MATCH will pass just a single value into the callback. Instead of updating a single output, it will update the dynamic output that is "matched" with.

ALLSMALLER is used to pass in the values of all of the targeted components on the page that have an index smaller than the index corresponding to the div. For example, ALLSMALLER makes it possible to filter results that are increasingly specific as the user applies each additional selection.

ALLSMALLER can only be used in input and state items, and must be used on a key that has MATCH in the output item(s). ALLSMALLER it isn't always necessary (you can usually use ALL and filter out the indices in your callback), but it will make your logic simpler.

Examples

if (interactive() ) {
  library(dash)

  # Simple example illustrating use of ALL selector
  app <- Dash$new()

  app$layout(htmlDiv(list(
    htmlButton("Add Filter", id="add-filter", n_clicks=0),
    htmlDiv(id="dropdown-container", children=list()),
    htmlDiv(id="dropdown-container-output")
  )))


  app$callback(
    output(id="dropdown-container", property = "children"),
    params = list(
      input(id = "add-filter", property = "n_clicks"),
      state(id = "dropdown-container", property = "children")
    ),
    display_dropdowns <- function(n_clicks, children){
      new_dropdown = dccDropdown(
        id=list(
          "index" = n_clicks,
          "type" = "filter-dropdown"
        ),
        options = lapply(c("NYC", "MTL", "LA", "TOKYO"), function(x){
          list("label" = x, "value" = x)
        })
      )
      children[[n_clicks + 1]] <- new_dropdown
      return(children)
    }
  )

  app$callback(
    output(id="dropdown-container-output", property="children"),
    params = list(
      input(id=list("index" = ALL, "type" = "filter-dropdown"), property= "value")
    ),
    display_output <- function(test){
      ctx <- app$callback_context()
      return(htmlDiv(
        lapply(seq_along(test), function(x){
          return(htmlDiv(sprintf("Dropdown %s = %s", x, test[[x]])))
        })
      ))
    }
  )

  app$run_server()

  # Simple example illustrating use of ALLSMALLER selector
  library(dash)

  df <- read.csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminder2007.csv',
                 stringsAsFactors = FALSE)

  app <- Dash$new()

  app$layout(htmlDiv(list(
    htmlButton("Add Filter", id = "add-filter-ex3", n_clicks = 0),
    htmlDiv(id = "container-ex3", children = list())
  )))

  app$callback(
    output('container-ex3', 'children'),
    params = list(
      input('add-filter-ex3', 'n_clicks'),
      state('container-ex3', 'children')
    ),
    display_dropdowns <- function(n_clicks, existing_children){
      new_children <- htmlDiv(list(
        dccDropdown(
          id = list("index" = n_clicks, "type" = "filter-dropdown-ex3"),
          options = lapply(unique(df$country), function(x){
            list("label" = x, "value" = x)
          }),
          value = unique(df$country)[n_clicks + 1]
        ),
        htmlDiv(id = list("index" = n_clicks, "type" = "output-ex3"),
                children = list(unique(df$country)[n_clicks + 1]))
      ))

      existing_children <- c(existing_children, list(new_children))
    }
  )

  app$callback(
    output(id = list("type" = "output-ex3", "index" = MATCH), property = "children"),
    params = list(
      input(id = list("type" = "filter-dropdown-ex3", "index" = MATCH), property = "value"),
      input(id = list("type" = "filter-dropdown-ex3", "index" = ALLSMALLER), property = "value")
    ),
    display_output <- function(matching_value, previous_values){
      previous_values_in_reversed_order = rev(previous_values)
      all_values = c(matching_value, previous_values_in_reversed_order)
      all_values = unlist(all_values)

      dff = df[df$country %in% all_values,]
      avgLifeExp = round(mean(dff$lifeExp), digits = 2)

      if (length(all_values) == 1) {
        return(
          htmlDiv(sprintf("%s is the life expectancy of %s.",
                  avgLifeExp,
                  matching_value))
        )
      } else if (length(all_values) == 2) {
        return(
          htmlDiv(sprintf("%s is the life expectancy of %s.",
                          avgLifeExp,
                          paste(all_values, collapse = " and ")))
        )
      } else {
        return(
          htmlDiv(sprintf("%s is the life expectancy of %s, and %s.",
                  avgLifeExp,
                  paste(all_values[-length(all_values)], collapse = " , "),
                  paste(all_values[length(all_values)])))
        )
      }
    }
  )

  app$run_server()

  # Simple example illustrating use of MATCH selector
  library(dash)

  app <- Dash$new()

  app$layout(htmlDiv(list(
    htmlButton("Add Filter", id="dynamic-add-filter", n_clicks=0),
    htmlDiv(id="dynamic-dropdown-container", children = list())
  )))

  app$callback(
    output(id="dynamic-dropdown-container", "children"),
    params = list(
      input("dynamic-add-filter", "n_clicks"),
      state("dynamic-dropdown-container", "children")
    ),
    display_dropdown <- function(n_clicks, children){
      new_element = htmlDiv(list(
        dccDropdown(
          id = list("index" = n_clicks, "type" = "dynamic-dropdown"),
          options = lapply(c("NYC", "MTL", "LA", "TOKYO"), function(x){
            list("label" = x, "value" = x)
          })
        ),
        htmlDiv(
          id = list("index" = n_clicks, "type" = "dynamic-output"),
          children = list()
        )
      ))

      children <- c(children, list(new_element))
      return(children)
    }
  )

  app$callback(
    output(id = list("index" = MATCH, "type" = "dynamic-output"), property= "children"),
    params = list(
      input(id=list("index" = MATCH, "type" = "dynamic-dropdown"), property= "value"),
      state(id=list("index" = MATCH, "type" = "dynamic-dropdown"), property= "id")
    ),
    display_output <- function(value, id){
      return(htmlDiv(sprintf("Dropdown %s = %s", id$index, value)))
    }
  )

  app$run_server()
}

plotly/dashR documentation built on June 12, 2022, 9:08 a.m.