interactivePlots
interactivePlots is a family of widgets that display interactive data plots generated with the plotly javascript library. “Interactive” means that user can select data points, adjust axis limits, and more, in their browser.
Interactive plots are a feature of many well-designed apps, but aren’t always required or the best tool. If WYSIWYG (“what you see is what you get”) images are more important, try the staticPlotBox.
How plotly works
When you fill a standard R Shiny plotOutput
, the plot is generated on the server and sent as image data to the browser. Every time the user wants to modify the image a request is sent to the server, which must spend time generating the revised image before sending it back. Shiny has basic image interaction processes like click and sweep selection, but to act on them a request must again be sent to the server as the browser does not have the data, just an image. Thus, it is a “server-side” approach.
The plotly library takes a “client-side” approach. The server is responsible for assembling a data object with everything needed to construct the plot that it sends to the browser. The plotly javascript library, running in the web browser, then renders to plot. Any interactions with the plot, and any ensuing adjustments to the plot image, are also handled in the browser, allowing for faster updates, especially for complex plots. The initial load of the plot can take a bit longer since more data needs to be sent to the browser, but then the experience is featured-rich and smooth.
Ways to use plotly in MDI apps
You do not need to use the MDI framework’s widgets. Feel free to use the functions of the R plotly package directly to make plots - the library is ready for use by all apps.
Here we describe wrappers around plotly intended to make it a bit easier to use a complex library.
The main interactive plot widgets are:
- interactiveBarplot = vertical or horizontal bar plots, with optional stacking
- interactiveScatterplot = X-Y plots of one or more series of data points
Using the interactivePlotBox wrapper functions
The main interactivePlot widgets just create the plot itself. You can wrap the plot in a box using the interactivePlotBox functions, which call interactiveScatterplot
, etc.
# interactivePlotBox_ui.R
interactivePlotBoxUI <- function(
id,
type = c("scatter", "bar", "density"),
..., # arguments passed to the relevant interactive plot UI function
#--------------------
title = NULL, # arguments passed to shinydashboard::box()
footer = NULL,
status = NULL,
solidHeader = FALSE,
background = NULL,
width = 6,
height = NULL,
collapsible = FALSE,
collapsed = FALSE,
#----------------------------------------
documentation = serverEnv$IS_DEVELOPER, # arguments passed to mdiHeaderLinks() via mdi::box()
reload = FALSE,
code = serverEnv$IS_DEVELOPER,
console = serverEnv$IS_DEVELOPER,
terminal = FALSE,
settings = FALSE
)
# interactivePlotBox_server.R
interactivePlotBoxServer <- function(
id,
type = c("scatter", "bar", "density"),
..., # arguments passed to the relevant interactive plot server function
#----------------------------
url = getDocumentationUrl( # arguments passed to activateMdiHeaderLinks()
"shiny/shared/session/modules/widgets/plots/interactivePlots/README",
framework = TRUE
),
reload = NULL,
baseDirs = NULL,
envir = parent.frame(),
dir = NULL,
settings = NULL,
template = settings, # for legacy support
#----------------------------
cacheKey = NULL, # arguments passed to settingsServer()
immediate = FALSE,
resettable = TRUE
)
where:
- type = the type of interactivePlot you require
- other arguments are passed to the functions indicated in the code blocks above
Basic plots - start simple and build
Even though they make multi-part interactive plots easier to assemble, the interactivePlots
widgets are still fairly complex. However, all options have defaults that allow you to generate initial interactive plots by providing only the plotData
argument. We recommend starting from there and adding to that base to build toward a richer data representation.
The following illustrates a very simple page with one of each kind of interactive plot (only widget-related code is shown):
# <scriptName>_ui.R
interactiveBarplotUI(ns('bar'))
interactiveScatterplotUI(ns('scatter'))
# <scriptName>_server.R
barData <- reactive({
data.frame(
value = 1:4,
group = c("Group1", "Group1", "Group2", "Group2"),
subgroup = c("Subgroup1", "Subgroup2", "Subgroup1", "Subgroup2"),
stringsAsFactors = FALSE
)
})
xyData <- reactive({
data.frame(
x = 1:4,
y = 1:4
)
})
interactiveBarplotServer('bar', barData)
interactiveScatterplotServer('scatter', xyData)
Common interactivePlots UI options
The interactivePlots UI functions take the following arguments in addition to ‘id’:
# interactiveXXXplotUI.R
interactiveBarplotUI <- function(id, height = '300px')
interactiveScatterplotUI <- function(id, height = '300px')
where all options are passed to plotlyOutput()
:
- height = a valid height, typically in px, used to scale the size of the plot
interactiveBarplotServer options
The interactiveBarplotServer
function takes the following arguments in addition to ‘id’:
# interactiveBarplot_server.R
interactiveBarplotServer <- function(
id,
#------------------------------------
plotData,
shareAxis = list(),
shareMargin = 0,
orientation = 'vertical',
#------------------------------------
range = NULL,
xtitle = NULL,
ytitle = NULL,
#------------------------------------
subgroupColors = NULL,
#------------------------------------
lines = NULL,
lineWidth = 2,
#------------------------------------
clickable = FALSE
)
where the following arguments define the plot data and structure:
- plotData = a reactive that returns a data.frame with columns ‘value’, ‘group’ and ‘subgroup’, a named vector of values, or a named list of such objects
- shareAxis = a list where x=TRUE or y=TRUE (not both) will cause >1 datasets to share that axis
- shareMargin = amount of space between stacked plots
- orientation = the orientation of the plotted bars, either horizontal or vertical
the following arguments define the axis properties:
- range = override the automatic range for the one numeric axis
- xtitle = x-axis label, character vector or a reactive
- ytitle = y-axis label, character vector or a reactive
the following arguments annotate data subgroups:
- subgroupColors = a color name or color palette used to color the subgroupings within each group
the following arguments create straight line overlays:
- lines = a function, reactive, or vector of axis values on the numeric axis where rules are drawn, or “mean” or “median”
- lineWidth = the width applied to
lines
and the following arguments define the plot interactions sent back to the R server (see below):
- clickable = whether plot should react to bar clicks
For bar plots, if plotData
is a named list, then a stack of plots is created.
interactiveScatterplotServer options
The interactiveScatterplotServer
function takes the following arguments in addition to ‘id’:
# interactiveScatterplot_server.R
interactiveScatterplotServer <- function(
id,
plotData,
accelerate = FALSE,
shareAxis = list(),
shareMargin = 0,
#------------------------------------
mode = "markers",
color = NA,
symbol = NA,
pointSize = 3,
lineWidth = 2,
#------------------------------------
overplot = NULL,
overplotMode = NULL,
overplotColor = NA,
overplotPointSize = 3,
overplotLineWidth = 2,
#------------------------------------
xtitle = "x",
xrange = NULL,
xzeroline = TRUE,
ytitle = "y",
yrange = NULL,
yzeroline = TRUE,
#------------------------------------
ticks = list(x = NULL, y = NULL),
grid = list(x = TRUE, y = TRUE),
selectable = FALSE,s
clickable = FALSE,
keyColumn = NULL,
#------------------------------------
hoverText = NULL,
labelCol = NULL,
labelDirs = list(x = 1, y = 1),
#------------------------------------
fitMethod = NULL,
fitColor = NA,
#------------------------------------
unityLine = FALSE,
hLines = NULL,
vLines = NULL,
#------------------------------------
distributions = NULL,
#------------------------------------
cacheReactive = NULL
)
where the following arguments define the plot data and structure:
- plotData = data to plot, a reactive that returns a data.frame with $x and $y, or a named list of such data.frames
- accelerate = if TRUE, use scattergl/WebGL (instead of SVG) to plot large data series much more quickly (with limitations)
- shareAxis = list where x=TRUE or y=TRUE (not both) will cause >1 datasets to share that axis; incompatible with overplotting or fitting
- shareMargin = the space between stacked plots
the following arguments define the properties of the main data points or lines:
- mode = how to plot; ‘markers’, ‘lines’, etc.
- color = colors, usually left as NA, i.e., default colors
- symbol = a vector or named list of symbols, or a column name in plotData()
- pointSize = a vector or named list of point sizes, or a column name in plotData()
- lineWidth = the width of data lines
the following arguments define the properties of repeated/extra points plotted on top of the original points:
- overplot = repeated/extra points plotted on top of the original points; if character, column of that name becomes the trace number
- overplotMode = analogous to mode, for
overplot
; if plotData is a named list, overplot must be NULL or an equal length list with the same names; defaults to the same mode as the main plot - overplotColor = analogous to color, for
overplot
- overplotPointSize = analogous to pointSize, for
overplot
- overplotLineWidth = analogous to lineWidth, for
overplot
the following arguments define the axis properties:
- xtitle = x-axis label, character vector or a reactive
- xrange = override the automatic x-axis range
- xzeroline = whether or not to show a line at x = 0
- ytitle = y-axis label, character vector or a reactive
- yrange = override the automatic y-axis range
- yzeroline = whether or not to show a line at y = 0
the following arguments define the plot’s ticks and grid:
- ticks = either NULL (default) or list(tick0=#, dtick=#) for the x (vertical) and y (horizontal) grids
- grid = either TRUE (default), FALSE (omitted), or a color value for the x (vertical) and y (horizontal) grids
the following arguments define the plot interactions sent back to the R server:
- selectable = whether point selection is enabled; either FALSE, TRUE (defaults to box select), ‘select’ (same as TRUE), ‘lasso’, ‘h’, or ‘v’
- clickable = whether plot should react to point clicks
- keyColumn = the name of the column in plotData to add as a click/select key; ends up in ‘customdata’ field of event_data
the following arguments define the labeling of data points:
- hoverText = character vector with hover text, or a function or reactive that returns one; if a 1-length character vector, hoverText is taken from that column of plotData()
- labelCol = the name of a column from which to read the text labels applied to a subset of points (use NA for unlabeled points)
- labelDirs = direction to draw the label arrow relative to x,y; 0=no offset, 1=farther along the axis, -1=opposite of 1 (i.e, to the inside)
the following arguments support curve fitting to the data points:
- fitMethod = a reactive that supplies a fit, a function(d) that returns a fit, or a method compatible with
fitTrendline
- fitColor = color of the curve fit
the following arguments add reference lines:
- unityLine = add a unity line after plotting the points
- hLines = a function, reactive, or vector of y-axis values for horizontal rules
- vLines = a function, reactive, or vector of x-axis values for vertical rules
the following arguments add data distributions:
- distributions = a function that returns a list of data.frames with $x and $y to plot as individual grey, dashed line distribution traces
and the following arguments create a key that is used to cache plots for faster server-side updates:
- cacheReactive = optional reactive with (hopefully simple to parse) values on which the plot depends; passed to
bindCache
as cache keys
interactiveBarplotServer return values
The interactiveBarplotServer
module returns a list as follows:
# interactiveBarplot_server.R
list(
clicked = clicked
)
where clicked is a reactiveVal
that returns plotly::event_data("plotly_click")
so that your module can react when a user clicks a data bar.
interactiveScatterplotServer return values
The interactiveScatterplotServer
module returns a list as follows:
# interactiveScatterplot_server.R
list(
selected = selected,
clicked = clicked,
fit = fit
)
where:
- selected = a
reactiveVal
that returnsplotly::event_data("plotly_selected")
so that your module can react when a user selects one or more data points - clicked = a
reactiveVal
that returnsplotly::event_data("plotly_click")
so that your module can react when a user clicks a data point - fit = a
reactiveVal
that returns the results offitMethod
applied toplotData
Plot stacking of multiple data sets
It is easier to read plots with multiple data sets, and takes less space, when they are shown in a stacked fashion with a shared x (or y) axis. This is accomplished by setting plotData
to be a named list of data.frames (rather than a single data frame) and using the shareAxis
and shareMargin
arguments to communicate whether to share an axis and how much space to put between shared-axis plots.
Overplot method for highlighting data points
You can choose to highlight data points in scatterplots by adjusting the point properties in plotData
, pointSize
, etc. However, this can be annoyingly difficult to get right, and unsatisfying in high-density plot where points get lost in the background.
interactiveScatterplot
offers an alternative approach in which you select a subset of data points in overplot
to plot a second time, on top of the primary plotting of plotData
. The points are thus configured entirely on their own and guaranteed to be visible.
Using plot interactions server-side
Many outcomes of a user’s interactions with your plot are handled client-side by plotly. However, many times you will also want to access them server-side, in your module.
The selected
and clicked
return values provide reactiveVals that your code can use to take appropriate actions. The contents of those reactiveVals are described in the plotly documentation, or simply use str(myPlot$selected())
when developing code to see what’s inside.
Common examples of things done in response to a plot interaction would be to update the plot itself or another plot or table that depends on user selections.
Additional references
For more detailed views of the modules’ code, see:
The following appStep server has several complete working examples: