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

KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 36128 110
New
alisinabh
Hey everyone i’ve developed a library for Jalaali calendar for elixir which supports converting Gregorian dates to Jalaali and vice vers...
New
wmnnd
Hi there, for my project DBLSQD, I needed a file storage solution that is a bit more flexible than Arc. Because I thought others might f...
New
bryanjos
Hi, I wanted share a small library we at Revelry Labs made for rendering react components from the server side. There are instructions fo...
New
dbern
I’m excited to announce that TaxJar has developed and open-sourced DateTimeParser. We developed it because we found a need to parse user ...
New
mathieuprog
Hello :waving_hand: Allow me to introduce you to Tz, an alternative time zone database support to Tzdata. Why another library? First a...
New
tmbb
PhoenixWS - Websockets over Phoenix Channels Source code on Github here: GitHub - tmbb/phoenix_ws: Websockets implemented over Phoenix Ch...
New
trisolaran
Hi! :waving_hand: I would like to present LiveSelect, a little library that I wrote to easily add a dynamic selection input to your LV f...
198 10858 107
New
zoltanszogyenyi
Hey everyone :waving_hand: Excited to join this forum - I am one of the founders and current project maintainers of a popular and open-s...
New
Jskalc
Hi! Today, after a couple weeks of development I’ve released v0.1 of LiveVue. It’s a seamless integration of Vue and Phoenix LiveView, i...
New

Other popular topics Top

JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
vegabook
I’m brand new to Phoenix and I have stripped one of the demo applications to the bone. I just want to get an svg up on the screen. Here i...
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
JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1144 53690 245
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 43622 214
New
saif
Hello everyone, Long time lurker first time poster here. I’ve recently begun working on Elixir full-time again! :raised_hands: It’s been...
New
marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New

We're in Beta

About us Mission Statement