klonowsk

klonowsk

Rx - run your R code in a persistent external Rscript process (Elixir ↔ R bridge)

Rx provides an Elixir ↔ R bridge heavily inspired by Pythonx. It includes support for LiveBook, the capture of static and interactive plots - the latter via plotly_ex, and Explorer. It extends and simplifies on the existing Rservex library, which I found somewhat limiting.

Alongside the default external process backend, Rx ships an experimental, optional, opt-in embedded native backend that loads R directly into the BEAM through a NIF. It exists for high-throughput workflows where the cost of crossing the process boundary dominates. The native backend is not built or loaded by default.

Set the environmental variable RX_BUILD_NIF=1 to build the C NIF, or RX_BUILD_RUST_NIF=1 to build the Rust NIF (needs Rust/Cargo from rustup). You’ll also need R’s headers and the embedded R shared library (libR.so on Linux, libR.dylib on macOS), plus make and a C compiler for the C path. Then init, as follows:

r_home = System.cmd("R", ["RHOME"], stderr_to_stdout: true) |> elem(0) |> String.trim()

lib_r_path =
  [Path.join([r_home, "lib", "libR.so"]), Path.join([r_home, "lib", "libR.dylib"])]
  |> Enum.find(&File.exists?/1)

Rx.system_init(backend: :native, r_home: r_home, lib_r_path: lib_r_path)

So, to run LiveBook with native C NIF:

RX_BUILD_NIF=1 livebook server

Tested on mac OS and Ubuntu Linux via WSL 2.

Released on github:

A few example notebooks are present under the notebooks directory on GitHub (notebooks/) for usage examples.

Any and all suggestions welcome.


Example code:

Mix.install([
  {:rx, "~> 0.1.0"},
  {:kino, "~> 0.19.0"},
  {:explorer, "~> 0.11"},
  {:kino_explorer, "~> 0.1.25"},
  {:plotly_ex, "~> 0.1"}
])


{obj, _} = Rx.eval("data.frame(x = 1:3, y = c('a','b','c'))", %{})
{:ok, df} = Rx.Explorer.from_r(obj)
df


df = Explorer.DataFrame.new(%{"x" => [1, 2, 3]})
{:ok, r_obj} = Rx.Explorer.to_r(df)
{result, _} = Rx.eval("sum(df$x)", %{"df" => r_obj})
Rx.decode(result)


[plot] = Rx.plot("plot(1:5)", %{})
Rx.Kino.image(plot)


[ggplot] =
  Rx.plot(
    """
    library(ggplot2)
    ggplot(mtcars, aes(wt, mpg)) + geom_point()
    """,
    %{}
  )
Rx.Kino.image(ggplot)


{r_plot, _} =
  Rx.eval(
    """
    plotly::plot_ly(mtcars, x=~wt, y=~mpg, color=~cyl, type = "scatter")
    """,
    %{}
  )

{:ok, fig} = Rx.Plotly.from_r(r_plot)
Plotly.show(fig)


{model, _} =
  Rx.eval(
    """
    lm(mpg ~ wt, mtcars)
    """,
    %{}
  )
Rx.print(model) |> IO.puts()

Where Next?

Popular in Announcing Top

maltoe
Hello! Came here to announce ChromicPDF, a pet project PDF generator I’ve been working on for the past few months. Why another PDF gener...
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New
Eiji
ExApi is a library that I’m developing now and hope release soon This library will allow to: list all apis list all api implementation...
New
oltarasenko
Dear Elixir community, After a year of development, bug fixes, and improvements, we are proudly ready to share the release of Crawly 0.1...
New
tmbb
I’ve been working on two packages (not on hex.pm yet) to build admin interfaces for phoenix apps: bureaucrat - which contains a bunch ...
New
blatyo
The best overview for how things are tied together is this presentation. Modules and functions are pretty well documented at this point, ...
New
hpopp
After just over two years in development, this latest version of Pigeon is what I finally consider done in regards to my original vision ...
New
Hal9000
Here is my first stab at this. README pasted below. https://github.com/Hal9000/elixir_random Comments and critiques are welcome. Thank...
New
zachdaniel
Ash Framework What is Ash? Ash Framework is a declarative, resource-oriented application development framework for Elixir. A resource can...
New
mattludwigs
Grizzly is a library for working with Z-Wave devices. Z-Wave is a low-frequency radio protocol for controlling smart home devices on a me...
New

Other popular topics Top

TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 41539 114
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 52341 488
New
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
Qqwy
Update: How to use the Blogs & Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3271 126479 1222
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

Latest on Elixir Forum

We're in Beta

About us Mission Statement