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()
Popular in Announcing
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance








