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()






















