All the material presented here, to the extent it is original, is available under CC-BY-SA.
I am running R 3.6.2, with recent update.packages()
.
needed <- c("rgl", "reticulate", "highcharter", "metricsgraphics",
"googleVis", "plotly", "ggvis", "ggplot2")
Script and data at https://github.com/rsbivand/BAN422_V20/raw/master/ban422_v20_wed.zip. Download to suitable location, unzip and use as basis.
Today, we’ll continue looking at how graphics work, touching on the internals
First, grid graphics and their use in lattice, ggplot2, vcd, tmap and other packages
Next, interactive graphics both simple and using external software, especially JavaScript rendering in web browsers
Finally, shiny and dashboards
Visualization is closely linked to aesthetic preferences
Consider visiting Lukasz Piwek’s site for plenty of ideas for visualization comparing approaches
Consider looking at pinp and tint as well as tufte for creating deliverables (HTML for conversion to PDF by printing to a PDF device, or PDF)
We can check the relative standing of graphics and grid from the CRAN package database, and add lattice and ggplot2 (Suggests are typically in examples):
db <- tools::CRAN_package_db()
types <- c("Depends", "Imports", "Suggests")
pkgs <- c("graphics", "grid", "lattice", "ggplot2")
(tbl <- sapply(types, function(type) sapply(pkgs,
function(pkg) length(db[grep(pkg, db[, type]), 1]))))
## Depends Imports Suggests
## graphics 316 1660 55
## grid 96 581 202
## lattice 169 247 249
## ggplot2 319 1531 715
class(tbl)
## [1] "matrix"
library(lattice)
barchart(tbl, auto.key=TRUE, horizontal=FALSE)
The grid and lattice entered as Recommended in R 1.5.0 in April 2002, and grid became a base package in 1.8.0 in October 2003
Some changes were made in grid for R 3, but its structure remains very stable
The gridBase and gridGraphics packages provide functions for capturing the state of the current device drawn with base graphics tools (see The gridGraphics Package)
One reason for this is the unsolved problem of testing graphics output for identity, to ensure that the same commands for the same data give the same output; for grid
objects this is feasible, but not for base graphics on interactive devices
Over and above the use of grid directly, the general-purpose packages lattice and ggplot2 build on grDevices and grid
In addition, it is worth mentioning the vcd (visualizing categorical data) and vcdExtra packages and a recent book on Discrete Data Analysis with R
Paul Murrell and co-authors have documented progress in some articles: Drawing Diagrams with R, What’s in a Name?, Debugging grid Graphics, The gridSVG Package,
We can combine grob
from different sources
b <- barchart(tbl, auto.key=TRUE,
horizontal=FALSE)
x11()
barplot(t(tbl), legend.text=TRUE,
args.legend=list(x="top", bty="n",
cex=0.8, y.intersp=3))
gridGraphics::grid.echo()
library(grid)
g <- grid.grab()
dev.off()
## png
## 2
grid.newpage()
gridExtra::grid.arrange(g, b, ncol=2)
grid pushes viewports onto a stack, then pops them, see R Graphics and vignettes
grid.rect(gp = gpar(lty = "dashed"))
vp <- viewport(width = 0.5, height = 0.5)
pushViewport(vp)
grid.rect(gp = gpar(col = "grey"))
grid.text("quarter of the page", y = 0.85)
pushViewport(vp)
grid.rect()
grid.text("quarter of the\nprevious viewport")
popViewport(2)
Just reading the print
method for ggplot
objects shows how close grid is under ggplot2.
ggplot2:::print.ggplot
## function (x, newpage = is.null(vp), vp = NULL, ...)
## {
## set_last_plot(x)
## if (newpage)
## grid.newpage()
## grDevices::recordGraphics(requireNamespace("ggplot2", quietly = TRUE),
## list(), getNamespace("ggplot2"))
## data <- ggplot_build(x)
## gtable <- ggplot_gtable(data)
## if (is.null(vp)) {
## grid.draw(gtable)
## }
## else {
## if (is.character(vp))
## seekViewport(vp)
## else pushViewport(vp)
## grid.draw(gtable)
## upViewport()
## }
## invisible(x)
## }
## <bytecode: 0x16a97f8>
## <environment: namespace:ggplot2>
There are various lower and higher-level ways of combining graphical output: some are described in a vignette in the egg package
df <- cbind(expand.grid(pkgs, types), n=c(tbl))
library(ggplot2)
gg <- ggplot(df, aes(x=Var1, y=n, fill=Var2)) + geom_col() +
xlab("") + guides(fill=guide_legend(title="")) +
theme(legend.position="top")
gg2 <- ggplotGrob(gg)
t <- gridExtra::tableGrob(as.data.frame(tbl))
gridExtra::grid.arrange(g, b, gg2, t, ncol=2, nrow=2)
Using the standard graphics devices, even if interactive, for interactive graphics is clunky
From early on, interactive graphics have used compiled (rggobi, rgl) external libraries or programs, or Java (iplots)
Most recent interactive graphics packages bundle JavaScript libraries: ggvis, plotly, googleVis, metricsgraphics, highcharter among many; client-side interactivity is the main benefit using JavaScript in a browser
Using external libraries may make functionalities vulnerable if not updated; see this example for JavaScript
a11 <- readRDS("../mon/dicook/a11.rds")
rggobi
rggobi passes data out to Ggobi for manipulation; Ggobi needs the GTK2 GUI toolbox (now outdated) and an XML library. Typical uses are manipulation of point clouds, project pursuit on point clouds, and interactive parallel coordinate plots.
library(rggobi)
ggobi(a11[,c(1, 4, 39:44)])
ggvis
ggvis is an RStudio package not unlike ggplot2 providing a range of data visualization functions mixing magrittr pipes and formulae. A key feature is integration with shiny (separate but related topic).
library(ggvis)
##
## Attaching package: 'ggvis'
## The following object is masked from 'package:ggplot2':
##
## resolution
a11 %>% ggvis(~ interaction(CNT, ST004D01T), ~ math_mean) %>% layer_boxplots()
plotly
The plotly package provides an interface to plotly, a company that “creates leading open source tools for composing, editing, and sharing interactive data visualization via the Web”, and lets you pay them if you don’t have time or skills:
library(plotly)
##
## Attaching package: 'plotly'
## The following objects are masked from 'package:ggvis':
##
## add_data, hide_legend
## The following object is masked from 'package:ggplot2':
##
## last_plot
## The following object is masked from 'package:stats':
##
## filter
## The following object is masked from 'package:graphics':
##
## layout
plot_ly(a11, x = ~math_mean, color = ~CNT, type = "box")
googleVis
googleVis provides an R interface to Google Charts, and is a mixture of R and JS code; JSON is the prime format for transferring data.
library(googleVis)
## Creating a generic function for 'toJSON' from package 'jsonlite' in package 'googleVis'
##
## Welcome to googleVis version 0.6.4
##
## Please read Google's Terms of Use
## before you start using the package:
## https://developers.google.com/terms/
##
## Note, the plot method of googleVis will by default use
## the standard browser to display its output.
##
## See the googleVis package vignettes for more details,
## or visit https://github.com/mages/googleVis.
##
## To suppress this message use:
## suppressPackageStartupMessages(library(googleVis))
plot(gvisHistogram(a11[a11$ST004D01T == "Male", c("math_mean", "read_mean", "sci_mean")]))
## starting httpd help server ...
## done
plot(gvisScatterChart(a11[, c("math_mean", "read_mean", "sci_mean")]))
metricsgraphics
metricsgraphics is another JS library
library(metricsgraphics)
a11$math_mean %>% mjs_hist()
highcharter
highcharter is yet another JS library
library(highcharter)
## Registered S3 method overwritten by 'xts':
## method from
## as.zoo.xts zoo
## Registered S3 method overwritten by 'quantmod':
## method from
## as.zoo.data.frame zoo
## Highcharts (www.highcharts.com) is a Highsoft software product which is
## not free for commercial and Governmental use
## Highcharts (www.highcharts.com) is a Highsoft
## software product which is not free for
## commercial and Governmental use
hcboxplot(x=a11$math_mean, var2=a11$ST004D01T,
var=a11$CNT)
## Warning: `cols` is now required.
## Please use `cols = c(data)`
reticulate
as an interface to matplotlib under pythonA recent blog points to the possibility of using the reticulate interface to Python to permit the use of matplotlib
library(reticulate)
np <- import("numpy")
plt <- import("matplotlib.pyplot")
phi <- np$arange(0, 3*np$pi, 0.0025)
x <- np$cos(5*phi)
y <- np$sin(3*phi)
plt$plot(x,y)
## [[1]]
## Line2D(_line0)
plt$savefig('sampleFileName.png')
#plt$show()
sampleFileName.png
rgl
interactive openGL 3D visualizationThe rgl package has provided an interface for manipulating 3D point clouds and objects for many years
library(rgl)
z <- rep(1, nrow(x))
rgl.open()
rgl.points(x, y, z)
rgl.snapshot("rgl_snapshot.png", top=TRUE)
rgl.close()
rgl_snapshot.png
shiny provides a client/server approach to interactive reporting; it is produced by RStudio, and they also provide hosting facilites (paid and free)
I have two shiny apps online at RStudio: Norwegian population and Norwegian population forecasts
Each app has (at least) two files ui.R
and server.R
; mine also have a data folder
shiny::runApp("shiny/NOR_fram", launch.browser=rstudioapi::viewer)
lets one run the app in the RStudio viewer window.
Each app needed two files, ui.R
with function shinyUI
and server.R
with shinyServer
(now may be one file app.R
with at least functions shinyServer
and shinyUI
)
shinyUI
provides the structure to be viewed on the client (usually a browser viewer)
shinyServer
provides the content, so must load and run R and packages and functions, using data that the server can access
Running the app provides an URL with a specified port, letting us see the internals made from shinyUI
Here are a number of links to blog posts and tutorials on using R graphics in Power BI: Interactive R visuals in Power BI, R Script Showcase, Create Power BI visuals using R