R: Add Controls to Interactive Plots

manipulateWidget {manipulateWidget} | R Documentation

## Add Controls to Interactive Plots

### Description

This function permits to add controls to an interactive plot created with packages like `dygraphs`, `highcharter` or `plotly` in order to change the input data or the parameters of the plot.

Technically, the function starts a shiny gadget. The R session is bloqued until the user clicks on "cancel" or "done". If he clicks on "done", then the the function returns the last displayed plot so the user can modify it and/or save it.

### Usage

    manipulateWidget(.expr, ..., .updateBtn = FALSE, .saveBtn = TRUE,
      .exportBtn = FALSE, .exportType = c("html2canvas", "webshot"),
      .updateBtnInit = FALSE, .viewer = c("pane", "window", "browser"),
      .compare = NULL, .compareOpts = compareOptions(), .showCompare = TRUE,
      .return = function(widget, envs) {     widget }, .width = NULL,
      .height = NULL, .runApp = TRUE)

### Arguments

`.expr` | expression to evaluate that returns an interactive plot of class `htmlwidget`. This expression is re-evaluated each time a control is modified.
`...` | One or more named control arguments created with functions `mwSlider`, `mwText`, etc. The name of each control is the name of the variable the controls modifies in the expression. One can also create a group of inputs by passing a list of such control arguments. for instance `mygroup = list(txt = mwText(""), nb = mwNumeric(0))` creates a group of inputs named mygroup with two inputs named "txt" and "nb".
`.updateBtn` | Should an update button be added to the controls ? If `TRUE`, then the graphic is updated only when the user clicks on the update button.
`.saveBtn` | Should an save button be added to the controls ? For saving output as html. Does not work in RStudio Viewer
`.exportBtn` | Should an export button be added to the controls ? For saving output as png. Does not work in RStudio Viewer
`.exportType` | `.exportBtn`, using `html2canvas` (default) and keeping current zoom, ... or using `webshot`
`.updateBtnInit` | In case of update button. Do you want to render graphics on init ?
`.viewer` | Controls where the gadget should be displayed. `"pane"` corresponds to the Rstudio viewer, `"window"` to a dialog window, and `"browser"` to an external web browser.
`.compare` | Sometimes one wants to compare the same chart but with two different sets of parameters. This is the purpose of this argument. It can be a character vector of input names or a named list whose names are the names of the inputs that should vary between the two charts. Each element of the list must be a vector or a list of length equal to the number of charts with the initial values of the corresponding parameter for each chart. It can also be `NULL`. In this case, the parameter is initialized with the default value for the two charts.
`.compareOpts` | List of options created `compareOptions`. These options indicate the number of charts to create and their disposition.
`.showCompare` | `logical`. In case of `.compare`. Show windows selection on menu ?
`.return` | A function that can be used to modify the output of `manipulateWidget`. It must take two parameters: the first one is the final widget, the second one is a list of environments containing the input values of each individual widget. The length of this list is one if .compare is null, two or more if it has been defined.
`.width` | Width of the UI. Used only on Rmarkdown documents with option `runtime: shiny`.
`.height` | Height of the UI. Used only on Rmarkdown documents with option `runtime: shiny`.
`.runApp` | (advanced usage) If true, a shiny gadget is started. If false, the function returns a `MWController` object. This object can be used to check with command line instructions the behavior of the application. (See help page of `MWController`). Notice that this parameter is always false in a non-interactive session (for instance when running tests of a package).

### Value

The result of the expression evaluated with the last values of the controls. It should be an object of class `htmlWidget`.

### Advanced Usage

The "normal" use of the function is to provide an expression that always return an `htmlwidget`. In such case, every time the user changes the value of an input, the current widget is destroyed and a new one is created and rendered.

Some packages provide functions to update a widget that has already been rendered. This is the case for instance for package `leaflet` with the function `leafletProxy`. To use such functions, `manipulateWidget` evaluates the parameter `.expr` with four extra variables:

- `.initial`: `TRUE` if the expression is evaluated for the first time and then the widget has not been rendered yet, `FALSE` if the widget has already been rendered.

- `.session`: A shiny session object.

- `.output`: ID of the output in the shiny interface.

- `.id`: Id of the chart. It can be used in comparison mode to make further customization without the need to create additional input controls.

You can take a look at the last example to see how to use these two variables to update a leaflet widget.

### Modify the returned widget

In some specific situations, a developer may want to use `manipulateWidget` in a function that waits the user to click on the "Done" button and modifies the widget returned by `manipulateWidget`. In such situation, parameter `.return` should be used so that `manipulateWidget` is the last function called. Indeed, if other code is present after, the custom function will act very weird in a Rmarkdown document with "runtime: shiny".

### Examples

    if (require(dygraphs)) {

      mydata <- data.frame(year = 2000+1:100, value = rnorm(100))
      manipulateWidget(dygraph(mydata[range[1]:range[2] - 2000, ], main = title),
                       range = mwSlider(2001, 2100, c(2001, 2100)),
                       title = mwText("Fictive time series"))

    }

    # Comparison mode
    if (require(dygraphs)) {

      mydata <- data.frame(
        year = 2000+1:100,
        series1 = rnorm(100),
        series2 = rnorm(100),
        series3 = rnorm(100)
      )

      manipulateWidget(
        dygraph(mydata[range[1]:range[2] - 2000, c("year", series)], main = title),
        range = mwSlider(2001, 2100, c(2001, 2100)),
        series = mwSelect(c("series1", "series2", "series3")),
        title = mwText("Fictive time series"),
        .compare = c("title", "series")
      )

      # Setting different initial values for each chart
      manipulateWidget(
        dygraph(mydata[range[1]:range[2] - 2000, c("year", series)], main = title),
        range = mwSlider(2001, 2100, c(2001, 2100)),
        series = mwSelect(c("series1", "series2", "series3")),
        title = mwText(),
        .compare = list(
          title = list("First chart", "Second chart"),
          series = NULL
        )
      )
    }

    # Grouping inputs
    if (require(dygraphs)) {

      mydata <- data.frame(year = 2000+1:100, value = rnorm(100))
      manipulateWidget(dygraph(mydata[range[1]:range[2] - 2000, ],
                               main = title, xlab = xlab, ylab = ylab),
                       range = mwSlider(2001, 2100, c(2001, 2100)),
                       "Graphical parameters" = mwGroup(
                          title = mwText("Fictive time series"),
                          xlab = mwText("X axis label"),
                          ylab = mwText("Y axis label")
                       )
                      )

    }

    # Example of conditional input controls
    #
    # In this example, we plot a x series against a y series. User can choose to
    # use points or lines. If he chooses lines, then an additional input is displayed
    # to let him control the width of the lines.
    if (require("plotly")) {

      dt <- data.frame (
        x = sort(runif(100)),
        y = rnorm(100)
      )

      myPlot <- function(type, lwd) {
        if (type == "points") {
          plot_ly(dt, x= ~x, y = ~y, type = "scatter", mode = "markers")
        } else {
          plot_ly(dt, x= ~x, y = ~y, type = "scatter", mode = "lines", line = list(width = lwd))
        }
      }

      manipulateWidget(
        myPlot(type, lwd),
        type = mwSelect(c("points", "lines"), "points"),
        lwd = mwSlider(1, 10, 1, .display = type == "lines")
      )

    }

    # Advanced Usage
    #
    # .expr is evaluated with extra variables .initial, .outputId and .session
    # that can be used to update an already rendered widget instead of replacing
    # it each time an input value is modified.
    #
    # Here we generate a UI that permits to change color and size of arbitrary
    # points on a map generated with leaflet.

    if (require(leaflet)) {
      lon <- rnorm(10, sd = 20)
      lat <- rnorm(10, sd = 20)

      myMapFun <- function(radius, color, initial, session, output) {
        if (initial) {
          # Widget has not been rendered
          map <- leaflet() %>% addTiles()
        } else {
          # widget has already been rendered
          map <- leafletProxy(output, session) %>% clearMarkers()
        }

        map %>% addCircleMarkers(lon, lat, radius = radius, color = color)
      }

      manipulateWidget(myMapFun(radius, color, .initial, .session, .output),
                       radius = mwSlider(5, 30, 10),
                       color = mwSelect(c("red", "blue", "green")))

    }

[Package manipulateWidget version 0.10.0 Index]