Jeroen Ooms (@opencpu) provides R
users a magical polyglot world of R, JavaScript, C, and C++. This is my
attempt to both thank him and highlight some of all that he has done.
Much of my new R depends on his work.
Ooms' Packages
metacran provides a list of all Jeroen's CRAN packages. Now, I wonder if any of his packages are in the Top Downloads.
jsonlite
Let's leverage the helpful meta again from
metacran and very quickly get some assistance
from hint-hint
jsonlite
.
library(jsonlite)
library(formattable)
library(tibble)
library(magrittr)
fromJSON("http://cranlogs.r-pkg.org/top/last-month/9") %>%
{as_tibble(rank=rownames(.$downloads),.$downloads)} %>%
rownames_to_column(var = "rank") %>%
format_table(
formatters = list(
area(row=which(.$package=="jsonlite")) ~ formatter("span", style="background-color:#D4F; width:100%")
)
)
rank | package | downloads |
---|---|---|
1 | Rcpp | 236316 |
2 | plyr | 208609 |
3 | ggplot2 | 201959 |
4 | stringi | 188252 |
5 | jsonlite | 175853 |
6 | digest | 174714 |
7 | stringr | 173835 |
8 | magrittr | 166437 |
9 | scales | 156694 |
V8
V8
gives R
its own embedded
JavaScript engine to leverage functionality in JavaScript that might not
exist in R
. For example, the
WebCola
constraint-based
layout engine offers valuable technology not available within R. Let's
partially recreate the smallgroups
example
all in R. You might notice that the previously mentioned jsonlite
is
essential to this workflow.
library(V8)
library(jsonlite)
library(scales)
ctx = new_context(global="window")
ctx$source("https://cdn.rawgit.com/tgdwyer/WebCola/master/WebCola/cola.min.js")
## [1] "true"
### small grouped example
group_json <- fromJSON(
system.file(
"htmlwidgets/lib/WebCola/examples/graphdata/smallgrouped.json",
package = "colaR"
)
)
# need to get forEach polyfill
ctx$source(
"https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.1.10/es5-shim.min.js"
)
# code to recreate small group example
js_group <- '
// console.assert does not exists
console = {}
console.assert = function(){};
var width = 960,
height = 500
graph = {
"nodes":[
{"name":"a","width":60,"height":40},
{"name":"b","width":60,"height":40},
{"name":"c","width":60,"height":40},
{"name":"d","width":60,"height":40},
{"name":"e","width":60,"height":40},
{"name":"f","width":60,"height":40},
{"name":"g","width":60,"height":40}
],
"links":[
{"source":1,"target":2},
{"source":2,"target":3},
{"source":3,"target":4},
{"source":0,"target":1},
{"source":2,"target":0},
{"source":3,"target":5},
{"source":0,"target":5}
],
"groups":[
{"leaves":[0], "groups":[1]},
{"leaves":[1,2]},
{"leaves":[3,4]}
]
}
var g_cola = new cola.Layout()
.linkDistance(100)
.avoidOverlaps(true)
.handleDisconnected(false)
.size([width, height]);
g_cola
.nodes(graph.nodes)
.links(graph.links)
.groups(graph.groups)
.start()
'
# run the small group JS code in V8
ctx$eval(js_group)
## [1] "[object Object]"
Now, WebCola
has done the hard work and laid out our nodes and links,
so let's get their positions.
nodes <- ctx$get('
graph.nodes.map(function(d){
return {name: d.name, x: d.x, y: d.y, height: d.height, width: d.width};
})
')
links <- ctx$get('
graph.links.map(function(d){
return {x1: d.source.x, y1: d.source.y, x2: d.target.x, y2: d.target.y}
})
')
Some great examples of packages employing V8
are
geojsonio
,
lawn
,
DiagrammeRsvg
,
rmapshaper
, and
daff
.
rjade
We got layout coordinates above. Let's use another one of Jeroen's
packages rjade
that provides
jade
(now called
pug) templates through V8
. rjade
will let us build a SVG
graph with our layout.
library(rjade)
library(htmltools)
svg <- jade_compile(
'
doctype xml
svg(version="1.1",xmlns="http://www.w3.org/2000/svg",xmlns:xlink="http://www.w3.org/1999/xlink",width="960px",height="500px")
each l in lines
line(style={fill:none, stroke:"lightgray"})&attributes({"x1": l.x1, "x2": l.x2, "y1": l.y1, "y2": l.y2})
each val in rects
g
rect(style={fill: fillColor})&attributes({"x": val.x - val.width/2, "y": val.y - val.height/2, "height": val.height - 6, "width": val.width - 6, rx: 5, ry: 5})
text&attributes({"x": val.x, "y": val.y, "dy": ".2em", "text-anchor":"middle"})= val.name
'
,pretty=T
)(rects = nodes, lines = links, fillColor = "lightgray")
HTML(svg)
rsvg
If we are not in the browser though with inline SVG
support, we very
likely will want a static image format such as png
or jpeg
. Of
course, Jeroen has that covered also with the crazy-speedy
rsvg
. Jeroen offers
base64
, but in this case we
will use base64enc
, since it allows raw
.
library(rsvg)
library(base64enc)
graph_png <- rsvg_png(charToRaw(svg))
tags$img(src=dataURI(graph_png), mime="image/png")
magick
Jeroen's newest package magick
is in my mind the coolest. magick
gives us all the power of
ImageMagick
as easy R
functions, and is pure wizardry. I am still shocked that it compiled
first try with absolutely no problems.
library(magick)
graph_img <- image_read(graph_png)
wizard_img <- image_read("http://www.imagemagick.org/image/wizard.png")
images <- image_annotate(
image_append(
c(
image_scale(image_crop(wizard_img, "600x600+100+100"), "100"),
image_crop(graph_img, "400x400+200+0")
)
),
"Ooms is a Wizard!",
size = 20,
color = "blue",
location = "+100+200"
)
tags$img(src=dataURI(image_write(images)), mime="image/png")
commonmark
I should note that this document was assembled in rmarkdown
. RStudio
gives us lots of tools for working with rmarkdown
, but Jeroen gives us
a powerful tool
commonmark
. Let's use it
to give our readers other options for output.
library(commonmark)
rmarkdown::render("Readme.Rmd", "Readme.md", output_format="md_document")
tex <- markdown_latex(readLines("Readme.md"))
cat(tex, file="Readme.tex")
This would convert markdown to LaTeX. As a test, I used commonmark
to make the html for this post.
Conclusion and Thanks
There are of course more packages, but I'll stop here. Jeroen Ooms truly
is a wizard, and the R
community is extraordinarily blessed to have
him. Thanks so much Jeroen.
For even more wizardry, be sure to check out opencpu from Jeroen, which makes R available as a web service.
No comments:
Post a Comment