Bringing R to Swift on macOS
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
Over Christmas break I teased some screencaps:
A more refined #rstats #swift “SwiftR” example. Simple Image view + some text views, a color picker and a button that runs
R-in-Swift code (like {reticulate} does for Python in R)
Note no ssd/hd storage round-trip for the plot.
Code snippet: https://t.co/fWaHnztUgd pic.twitter.com/y5m1I16tCB
— Caliban's War (@hrbrmstr) December 28, 2020
Final teaser for #rstats R-in-Swift (SwiftR) since I _think_ I've 'd all memory leaks and refined the example project. The displayed 10,… numbers come right from sample()'d R vector and the fill color live refreshes fast b/c {magick} is magical. Shld have repo up Thu. pic.twitter.com/boGa5ej9FZ
— Caliban's War (@hrbrmstr) December 29, 2020
of some almost-natural “R” looking code (this is a snippet):
Button("Run") { do { // calls to R can fail so there are lots of "try"s; poking at less ugly alternatives // handling dots in named calls is a WIP _ = try R.evalParse("options(tidyverse.quiet = TRUE )") // in practice this wld be called once in a model try R.library("ggplot2") try R.library("hrbrthemes") try R.library("magick") // can mix initialiation of an R list with Swift and R objects let mvals: RObject = [ "month": [ "Jan", "Feb", "Mar", "Apr", "May", "Jun" ], "value": try R.sample(100, 6) ] // ggplot2! `mvals` is above, `col.hexValue` comes from the color picker // can't do R.as.data.frame b/c "dots" so this is a deliberately exposed alternate call let gg = try R.ggplot(R.as_data_frame(mvals)) + R.geom_col(R.aes_string("month", "value"), fill: col.hexValue) + // supports both [un]named R.scale_y_comma() + R.labs( x: rNULL, y: "# things", title: "Monthly Bars" ) + R.theme_ipsum_gs(grid: "Y") // an alternative to {magick} could be getting raw SVG from {svglite} device // we get Image view width/height and pass that to {magick} // either beats disk/ssd round-trip let fig = try R.image_graph( width: Double(imageRect.width), height: Double(imageRect.height), res: 144 ) try R.print(gg) _ = R.dev_off() // can't do R.dev.off b/c "dots" so this is a deliberately exposed alternate call let res = try R.image_write(fig, path: rNULL, format: "png") imgData = Data(res) // "imgData" is a reactive SwiftUI bound object; when it changes Image does too } catch { } }
that works in Swift as part of a SwiftUI app that displays a ggplot2 plot inside of a macOS application.
It doesn’t shell out to R, but uses Swift 5’s native abilities to interface with R’s C interface.
I’m not ready to reveal that SwiftR code/library just yet (break’s over and the core bits still need some tweaking) but I can provide some interim resources with an online book about working with R’s C interface from Swift on macOS. It is uninspiringly called SwiftR — Using R from Swift.
There are, at present, six chapters that introduce the Swift+R concepts via command line apps. These aren’t terribly useful (shebanged R scripts work just fine, #tyvm) in and of themselves, but command line machinations are a much lower barrier to entry than starting right in with SwiftUI (that starts in chapter seven).
FIN
If you’ve wanted a reason to burn ~20GB of drive space with an Xcode installation and start to learn Swift (or learn more about Swift) then this is a resource for you.
The topics in the chapters are also a fairly decent (albeit incomplete) overview of R’s C interface and also how to work with C code from Swift in general.
So, take advantage of the remaining pandemic time and give it a .
Feedback is welcome in the comments or the book code repo (book source repo is in progress).
Hope everyone has a safe and strong new year!
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.