The Figure Data Structure in R

The structure of a figure - data, traces and layout explained in R


New to Plotly?

Plotly is a free and open-source graphing library for R. We recommend you read our Getting Started guide for the latest installation or upgrade instructions, then move on to our Plotly Fundamentals tutorials or dive straight in to some Basic Charts tutorials.

Overview

Plotly's R graphing library makes interactive, publication-quality graphs. Examples of how to make line plots, scatter plots, area charts, bar charts, error bars, box plots, histograms, heatmaps, subplots, multiple-axes, and 3D (WebGL based) charts. Plotly.R is free and open source and you can view the source, report issues or contribute on GitHub. The rendering process uses the Plotly.js JavaScript library under the hood. Figures can be represented in R either as lists or as instances of the plotly , and are serialized as text in JavaScript Object Notation (JSON) before being passed to Plotly.js.

Viewing the underlying data structure for any plotly object, can be done via dput(fig).

library(plotly) 

fig <- plot_ly() %>% 
  add_lines(x = c("a","b","c"), y = c(1,3,2))%>% 
  layout(title="sample figure", xaxis = list(title = 'x'), yaxis = list(title = 'y'), plot_bgcolor = "#c7daec") 

str(fig$x) 
## List of 7
##  $ visdat     :List of 1
##   ..$ 2f8c3c532958:function ()  
##  $ cur_data   : chr "2f8c3c532958"
##  $ attrs      :List of 2
##   ..$ 2f8c3c532958:List of 3
##   .. ..$ alpha_stroke: num 1
##   .. ..$ sizes       : num [1:2] 10 100
##   .. ..$ spans       : num [1:2] 1 20
##   ..$ 2f8c3c532958:List of 8
##   .. ..$ alpha_stroke: num 1
##   .. ..$ sizes       : num [1:2] 10 100
##   .. ..$ spans       : num [1:2] 1 20
##   .. ..$ x           : chr [1:3] "a" "b" "c"
##   .. ..$ y           : num [1:3] 1 3 2
##   .. ..$ type        : chr "scatter"
##   .. ..$ mode        : chr "lines"
##   .. ..$ inherit     : logi TRUE
##   .. ..- attr(*, "class")= chr [1:2] "plotly_line" "list"
##  $ layout     :List of 3
##   ..$ width : NULL
##   ..$ height: NULL
##   ..$ margin:List of 4
##   .. ..$ b: num 40
##   .. ..$ l: num 60
##   .. ..$ t: num 25
##   .. ..$ r: num 10
##  $ source     : chr "A"
##  $ config     :List of 2
##   ..$ modeBarButtonsToAdd: chr [1:2] "hoverclosest" "hovercompare"
##   ..$ showSendToCloud    : logi FALSE
##  $ layoutAttrs:List of 1
##   ..$ 2f8c3c532958:List of 4
##   .. ..$ title       : chr "sample figure"
##   .. ..$ xaxis       :List of 1
##   .. .. ..$ title: chr "x"
##   .. ..$ yaxis       :List of 1
##   .. .. ..$ title: chr "y"
##   .. ..$ plot_bgcolor: chr "#c7daec"
##  - attr(*, "TOJSON_FUNC")=function (x, ...)
fig

Accessing figure structures in Dash

Dash for R is an open-source framework for building analytical applications, with no Javascript required, and it is tightly integrated with the Plotly graphing library.

Learn about how to install Dash for R at https://dashr.plot.ly/installation.

Everywhere in this page that you see fig, you can display the same figure in a Dash for R application by passing it to the figure argument.

library(dash) 
library(dashCoreComponents) 
library(dashHtmlComponents) 
library(plotly) 

fig <- plot_ly() %>% 
  add_lines(x = c("a","b","c"), y = c(1,3,2))%>% 
  layout(title="sample figure") 

app <- Dash$new() 

app$layout( 
  htmlDiv( 
    list( 
      dccGraph(id = 'graph', figure=fig), 
      htmlPre( 
        id='structure', 
        style = list(border = 'thin lightgrey solid', 
                     overflowY = 'scroll', 
                     height = '275px') 
      ) 
    ) 
  ) 
) 
app$callback( 
  output(id = 'structure', property='children'), 
  params=list(input(id='graph', property='figure')), 
  function(fig_json) { 
    plotly_json <- function(p, ...) { 
      plotly:::to_JSON(plotly_build(p), ...) 
    } 
    jfig <- plotly_json(fig, pretty = TRUE) 
    return(jfig) 
  }) 

After executing this code, give app$run_server() in the console to start the dash.

Figures as Trees of Attributes

Plotly.js supports inputs adhering to a well-defined schema, whose overall architecture is explained in this page and which is exhaustively documented in the Figure Reference (which is itself generated from a machine-readable JSON representation of the schema). Figures are represented as trees with named nodes called "attributes".

Attributes are referred to in text and in the Figure Reference by their names. For example "layout = list(width = NULL)" refers to the attribute whose key is "width" inside a list which is the value associated with a key "layout" at the root of the figure.

When manipulating a plotly object, attributes can be set directly using R object attributes e.g. fig.layout.title.font.family="Open Sans" or using fig %>% layout(title = list(font = 'Open Sans')).

When building a figure, it is not necessary to populate every attribute of every object. At render-time, the JavaScript layer will compute default values for each required unspecified attribute, depending upon the ones that are specified, as documented in the Figure Reference. An example of this would be layout.xaxis.range, which may be specified explicitly, but if not will be computed based on the range of x values for every trace linked to that axis. The JavaScript layer will ignore unknown attributes or malformed values, although the plotly module provides R-side validation for attribute values.

The Top-Level data Attribute

The first of the three top-level attributes of a figure is data, whose value must be a list referred to as "traces".

  • Each trace has one of more than 40 possible types (see below for a list organized by subplot type, including e.g. scatter, bar, pie, surface, choropleth etc), and represents a set of related graphical marks in a figure. Each trace must have a type attribute which defines the other allowable attributes.
  • Each trace is drawn on a single subplot whose type must be compatible with the trace's type, or is its own subplot (see below).
  • Traces may have a single legend entry, with the exception of pie and funnelarea traces (see below).
  • Certain trace types support continuous color, with an associated colorbar, which can be controlled by attributes either within the trace, or within the layout when using the coloraxis attribute.

The Top-Level layout Attribute

The second of the three top-level attributes of a figure is layout, whose value is referred to in text as "the layout" and must be a list, containing attributes that control positioning and configuration of non-data-related parts of the figure such as:

  • Dimensions and margins, which define the bounds of "paper coordinates" (see below)
  • Title and legend (positionable in container and/or paper coordinates)
  • Color axes and associated color bars (positionable in paper coordinates)
  • Subplots of various types on which can be drawn multiple traces and which are positioned in paper coordinates:
    • xaxis, yaxis, xaxis2, yaxis3 etc: X and Y cartesian axes, the intersections of which are cartesian subplots
    • scene, scene2, scene3 etc: 3d scene subplots
    • ternary, ternary2, ternary3, polar, polar2, polar3, geo, geo2, geo3, mapbox, mapbox2, mabox3 etc: ternary, polar, geo or mapbox subplots
  • Non-data marks which can be positioned in paper coordinates, or in data coordinates linked to 2d cartesian subplots:
  • Controls which can be positioned in paper coordinates and which can trigger Plotly.js functions when interacted with by a user:

The Top-Level frames Attribute

The third of the three top-level attributes of a figure is frames, whose value must be a list that define sequential frames in an animated plot. Each frame contains its own data attribute as well as other parameters. Animations are usually triggered and controlled via controls defined in layout.sliders and/or layout.updatemenus

Positioning With Paper, Container Coordinates, or Axis Domain Coordinates

Various figure components configured within the layout of the figure support positioning attributes named x or y, whose values may be specified in "paper coordinates" (sometimes referred to as "plot fractions" or "normalized coordinates"). Examples include layout.xaxis.domain or layout.legend.x or layout.annotation.x.

Positioning in paper coordinates is not done in absolute pixel terms, but rather in terms relative to a coordinate system defined with an origin (0,0) at (layout.margin.l, layout.margin.b) and a point (1,1) at (layout.width-layout.margin.r, layout.height-layout.margin.t) (note: layout.margin values are pixel values, as are layout.width and layout.height). Paper coordinate values less than 0 or greater than 1 are permitted, and refer to areas within the plot margins.

To position an object in "paper" coordinates, the corresponding axis reference is set to "paper". For instance a shape's xref attribute would be set to "paper" so that the x value of the shape refers to its position in paper coordinates.

Note that the contents of the layout.margin attribute are by default computed based on the position and dimensions of certain items like the title or legend, and may be made dependent on the position and dimensions of tick labels as well when setting the layout.xaxis.automargin attribute to True. This has the effect of automatically increasing the margin values and therefore shrinking the physical area defined between the (0,0) and (1,1) points. Positioning certain items at paper coordinates less than 0 or greater than 1 will also trigger this behavior. The layout.width and layout.height, however, are taken as givens, so a figure will never grow or shrink based on its contents.

The figure title may be positioned using "container coordinates" which have (0,0) and (1,1) anchored at the bottom-left and top-right of the figure, respectively, and therefore are independent of the values of layout.margin.

Furthermore, shapes, annotations, and images can be placed relative to an axis's domain so that, for instance, an x value of 0.5 would place the object halfway along the x-axis, regardless of the domain as specified in the layout.xaxis.domain attribute. This behavior can be specified by adding ' domain' to the axis reference in the axis referencing attribute of the object. For example, setting yref = 'y2 domain' for a shape will refer to the length and position of the axis named y2.

2D Cartesian Trace Types and Subplots

The most commonly-used kind of subplot is a two-dimensional Cartesian subplot. Traces compatible with these subplots support xaxis and yaxis attributes whose values must refer to corresponding objects in the layout portion of the figure. For example, if xaxis="x", and yaxis="y" (which is the default) then this trace is drawn on the subplot at the intersection of the axes configured under layout.xaxis and layout.yaxis, but if xaxis="x2" and yaxis="y3" then the trace is drawn at the intersection of the axes configured under layout.xaxis2 and layout.yaxis3. Note that attributes such as layout.xaxis and layout.xaxis2 etc do not have to be explicitly defined, in which case default values will be inferred. Multiple traces of different types can be drawn on the same subplot.

X- and Y-axes support the type attribute, which enables them to represent continuous values (type="linear", type="log"), temporal values (type="date") or categorical values (type="category", type="multicategory). Axes can also be overlaid on top of one another to create dual-axis or multiple-axis charts. 2-d cartesian subplots lend themselves very well to creating "small multiples" figures, also known as facet or trellis plots.

The following trace types are compatible with 2d-cartesian subplots via the xaxis and yaxis attributes:

3D, Polar and Ternary Trace Types and Subplots

Beyond 2D cartesian subplots, figures can include three-dimensional cartesian subplots, polar subplots and ternary subplots. The following trace types support attributes named scene, polar or ternary, whose values must refer to corresponding objects in the layout portion of the figure i.e. ternary="ternary2" etc. Note that attributes such as layout.scene and layout.ternary2 etc do not have to be explicitly defined, in which case default values will be inferred. Multiple traces of a compatible type can be placed on the same subplot.

The following trace types are compatible with 3D subplots via the scene attribute, which contains special camera controls:

The following trace types are compatible with polar subplots via the polar attribute:

The following trace types are compatible with ternary subplots via the ternary attribute:

Map Trace Types and Subplots

Figures can include two different types of map subplots: geo subplots for outline maps and mapbox subplots for tile maps. The following trace types support attributes named geo or mapbox, whose values must refer to corresponding objects in the layout i.e. geo="geo2" etc. Note that attributes such as layout.geo2 and layout.mapbox etc do not have to be explicitly defined, in which case default values will be inferred. Multiple traces of a compatible type can be placed on the same subplot.

The following trace types are compatible with geo subplots via the geo attribute:

The following trace types are compatible with mapbox subplots via the mapbox attribute:

Traces Which Are Their Own Subplots

Certain trace types cannot share subplots, and hence have no attribute to map to a corresponding subplot in the layout. Instead, these traces are their own subplot and support a domain attribute for position, which enables the trace to be positioned in paper coordinates (see below). With the exception of pie and funnelarea, such traces also do not support legends (see below)

The following trace types are their own subplots and support a domain attribute:

Carpet Trace Types and Subplots

Certain trace types use traces of type carpet as a subplot. These support a carpet attribute whose value must match the value of the carpet attribute of the carpet trace they are to be drawn on. Multiple compatible traces can be placed on the same carpet trace.

The following trace types are compatible with carpet trace subplots via the carpet attribute:

Trace Types, Legends and Color Bars

Traces of most types can be optionally associated with a single legend item in the legend. Whether or not a given trace appears in the legend is controlled via the showlegend attribute. Traces which are their own subplots (see above) do not support this, with the exception of traces of type pie and funnelarea for which every distinct color represented in the trace gets a separate legend item. Users may show or hide traces by clicking or double-clicking on their associated legend item. Traces that support legend items also support the legendgroup attribute, and all traces with the same legend group are treated the same way during click/double-click interactions.

The fact that legend items are linked to traces means that when using discrete color, a figure must have one trace per color in order to get a meaningful legend.

Traces which support continuous color can also be associated with color axes in the layout via the coloraxis attribute. Multiple traces can be linked to the same color axis. Color axes have a legend-like component called color bars. Alternatively, color axes can be configured within the trace itself.

What About Dash?

Dash for R is an open-source framework for building analytical applications, with no Javascript required, and it is tightly integrated with the Plotly graphing library.

Learn about how to install Dash for R at https://dashr.plot.ly/installation.

Everywhere in this page that you see fig, you can display the same figure in a Dash for R application by passing it to the figure argument of the Graph component from the built-in dashCoreComponents package like this:

library(plotly)

fig <- plot_ly() 
# fig <- fig %>% add_trace( ... )
# fig <- fig %>% layout( ... ) 

library(dash)
library(dashCoreComponents)
library(dashHtmlComponents)

app <- Dash$new()
app$layout(
    htmlDiv(
        list(
            dccGraph(figure=fig) 
        )
     )
)

app$run_server(debug=TRUE, dev_tools_hot_reload=FALSE)