Type: | Package |
Title: | 'WebVR' Data Visualizations with 'RStudio Shiny' and 'Mozilla A-Frame' |
Version: | 1.0.1 |
Description: | Make R data available in Web-based virtual reality experiences for immersive, cross-platform data visualizations. Includes the 'gg-aframe' JavaScript package for a Grammar of Graphics declarative HTML syntax to create 3-dimensional data visualizations with 'Mozilla A-Frame' https://aframe.io. |
License: | AGPL-3 |
Encoding: | UTF-8 |
LazyData: | true |
Imports: | shiny, htmlwidgets, htmltools |
RoxygenNote: | 5.0.1 |
Suggests: | knitr, rmarkdown, scales, dplyr |
VignetteBuilder: | knitr |
NeedsCompilation: | no |
Packaged: | 2017-11-24 17:30:32 UTC; vrbox |
Author: | William Murphy [cre, aut] |
Maintainer: | William Murphy <william.murphy.rd@gmail.com> |
Repository: | CRAN |
Date/Publication: | 2017-11-26 15:29:43 UTC |
WebVR Data Visualizations
Description
Make R data available in Web-based virtual reality experiences for immersive, cross-platform data visualizations. Includes the 'gg-aframe' JavaScript package for a Grammar of Graphics declarative HTML syntax to create 3-dimensional visualizations.
Examples
# Example Shiny app from package vignette
if (interactive()) {
library(shiny)
library(dplyr)
library(scales)
library(shinyaframe)
shinyApp(
ui = fluidPage(
aDataSceneOutput(
# attributes and child elements provided as arguments
# server output variable name
outputId = "mydatascene",
# add backdrop
environment = "",
# gg-aframe plot syntax
atags$entity(
# an empty string sets attributes with no additional properties
plot = "",
# sizable scale option uses polyhedra scaled for equivalent volumes
`scale-shape` = "sizable",
position = "0 1.6 -1.38",
atags$entity(
`layer-point` = "",
`data-binding__sepal.length`="target: layer-point.x",
`data-binding__sepal.width`="target: layer-point.y",
`data-binding__petal.length`="target: layer-point.z",
`data-binding__species`="target: layer-point.shape",
`data-binding__petal.width.size`="target: layer-point.size",
`data-binding__species.color`="target: layer-point.color"
),
atags$entity(
`guide-axis` = "axis: x",
`data-binding__xbreaks` = "target: guide-axis.breaks",
`data-binding__xlabels` = "target: guide-axis.labels",
`data-binding__xtitle` = "target: guide-axis.title"
),
atags$entity(
`guide-axis` = "axis: y",
`data-binding__ybreaks` = "target: guide-axis.breaks",
`data-binding__ylabels` = "target: guide-axis.labels",
`data-binding__ytitle` = "target: guide-axis.title"
),
atags$entity(
`guide-axis` = "axis: z",
`data-binding__zbreaks` = "target: guide-axis.breaks",
`data-binding__zlabels` = "target: guide-axis.labels",
`data-binding__ztitle` = "target: guide-axis.title"
),
atags$entity(
`guide-legend` = "aesthetic: shape",
`data-binding__shapetitle` = "target: guide-legend.title"
),
atags$entity(
`guide-legend` = "aesthetic: size",
`data-binding__sizebreaks` = "target: guide-legend.breaks",
`data-binding__sizelabels` = "target: guide-legend.labels",
`data-binding__sizetitle` = "target: guide-legend.title"
),
atags$entity(
`guide-legend` = "aesthetic: color",
`data-binding__colorbreaks` = "target: guide-legend.breaks",
`data-binding__colorlabels` = "target: guide-legend.labels",
`data-binding__colortitle` = "target: guide-legend.title"
),
# animate the plot rotation
atags$other('animation', attribute = "rotation",
from = "0 45 0", to = "0 405 0",
dur = "10000", `repeat` = "indefinite")
)
)
),
server = function(input, output, session) {
output$mydatascene <- renderADataScene({
names(iris) <- tolower(names(iris))
# Margin in (0,1) scale keeps polyhedra from sticking out of plot area
positional_to <- c(0.01, 0.99)
# convert to #RRGGBB color
color_scale = setNames(rainbow(3, 0.75, 0.5, alpha = NULL),
unique(iris$species))
iris %>%
# scale positional data
mutate_if(is.numeric, rescale, to = positional_to) %>%
# scale size data to relative percentage, using cube root to correct
# for radius->volume perception bias
mutate(petal.width.size = rescale(petal.width^(1/3), to = c(0.5, 2)),
species.color = color_scale[species]) ->
iris_scaled
# provide guide info
make_guide <- function (var, aes, breaks = c(0.01, 0.5, 0.99)) {
guide = list()
domain = range(iris[[var]])
guide[[paste0(aes, "breaks")]] <- breaks
guide[[paste0(aes, "labels")]] <- c(domain[1],
round(mean(domain), 2),
domain[2])
guide[[paste0(aes, "title")]] <- var
guide
}
Map(make_guide,
var = c("sepal.length", "sepal.width", "petal.length"),
aes = c("x", "y", "z")) %>%
# repeat radius adjustment in the guide
c(list(make_guide("petal.width", "size", c(0.5, 1.25, 2)^(1/3)))) %>%
Reduce(f = c) ->
guides
guides$shapetitle = "species"
guides$colortitle = "species"
guides$colorbreaks = color_scale
guides$colorlabels = names(color_scale)
# convert data frame to list and combine with guides list
aDataScene(c(iris_scaled, guides))
})
}
)
}
A-Frame Scene with R data
Description
Create an HTML widget to sync R data with an A-Frame scene via the data-binding A-Frame component.
Usage
aDataScene(data, elementId = NULL)
Arguments
data |
A data frame or a list of vectors, matrices, and/or data frames |
elementId |
Optionally define the output HTML element |
Details
Data will be synced to the data-binding
system from the
gg-aframe JavaScript
library for A-Frame. Data can be bound to automatically update components
in the scene with the data-binding
A-Frame component. Repeat
calls (e.g. within a Shiny reactive expression) will update the
data-binding
store and refresh bound components with the new data.
If data
is a data frame, each variable will be available, by name,
as a JavaScript Array in the scene data store (i.e. long form).
If it is a list, each list item will be available, by name, as a
JavaScript Array in the scene data store. Data frames within the list
will be available as an array of Objects, with each object
representing a row from the data frame (i.e. wide form).
To send multiple data frames in long form, combine them with
c
, and each column will be available by name
in the A-Frame data-binding
system. To send multiple
data frames in wide form, combine them as named items in
a list
, and each data frame will be available as an array of
objects (rows) under the name used.
Note: aDataScene
is only compatible for use in Shiny
apps viewed with a modern Web browser and internet connection.
WebVR data visualizations are not available in Rmd documents, R Notebooks,
or the RStudio Viewer at this time.
See Also
Examples
library(dplyr)
library(scales)
# Execute within a renderADataScene call in a Shiny server
iris %>%
# scale positional data to (0,1)
mutate_if(is.numeric, rescale) %>%
# make data available in JavaScript
aDataScene()
Shiny bindings for aDataScene
Description
Output and render functions for using aDataScene within Shiny applications.
Usage
aDataSceneOutput(outputId, ..., skipDependencies = FALSE)
renderADataScene(expr, env = parent.frame(), quoted = FALSE)
Arguments
outputId |
output variable to read from |
... |
Attributes, A-Frame components, and/or child elements for output in HTML. |
skipDependencies |
Option to omit packaged A-Frame JavaScript libraries. See details. |
expr |
An expression that returns a call to |
env |
The environment in which to evaluate |
quoted |
Is |
Details
A-Frame v0.7.1, gg-aframe v0.2.3, and
aframe-environment-component v1.0.0 come packaged with
shinyaframe. To use different versions, set skipDependencies
to TRUE
and source the libraries directly (for
example with includeScript
or
tag
).
See Also
'gg-aframe' syntax documentation
Examples
# Simple 3D scatterplot.
# See package vignette for additional asethetics, guides, and legends
if (interactive()) {
library(dplyr)
library(shiny)
library(scales)
shinyApp(
ui = fluidPage(
aDataSceneOutput(
outputId = "mydatascene",
# gg-aframe plot syntax
atags$entity(
plot = "", position = "0 1.6 -1.38", rotation = "0 45 0",
atags$entity(
`layer-point` = "", `mod-oscillate` = "",
`data-binding__sepal.length`="target: layer-point.x",
`data-binding__sepal.width`="target: layer-point.y",
`data-binding__petal.length`="target: layer-point.z",
# add 4th positional by animating y position between two mappings
`data-binding__petal.width`="target: mod-oscillate.y",
`data-binding__species`="target: layer-point.shape"
)
)
)
),
server = function(input, output, session) {
output$mydatascene <- renderADataScene({
names(iris) <- tolower(names(iris))
iris %>%
# scale positional data
mutate_if(is.numeric, rescale) %>%
aDataScene()
})
}
)
}
A-Frame Custom Elements
Description
Functions to output A-Frame's custom HTML elements
Usage
aframeScene(...)
aframeAssets(...)
aframeMixin(...)
aframeEntity(...)
aframeSphere(...)
aframeBox(...)
aframePrimitive(primitive = "entity", ...)
atags
Arguments
... |
Attributes, components, and/or child elements |
primitive |
Primitive name (excluding the "a-") |
Format
The atags
list contains all of these
tag functions for convenient access.
Details
These functions are just simple wrappers for
tag
to output common A-Frame custom elements.
Functions
-
aframeScene
: Top level scene entity -
aframeAssets
: Specify assets for pre-loading -
aframeMixin
: Reusable component specifications -
aframeEntity
: Generic entity -
aframeSphere
: Sphere primitive -
aframeBox
: Box primitive -
aframePrimitive
: All other primitives
See Also
Examples
# Construct A-Frame HTML syntax for a 3D scene with a red box and blue sky
atags$scene(
atags$box(color = "red", position = "0 0.5 -3"),
atags$other("sky", color = "#89b6ff")
)