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

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 54260 488
New
Crowdhailer
Raxx is an alternative to Plug and is inspired by projects such as Rack(Ruby) and Ring(Clojure). 1.0-rc.1 is now available. To use it re...
New
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
fuelen
Hey folks! Want to present a toolkit for writing command-line user interfaces. It provides a convenient interface for colorizing text...
New
benlime
LiveMotion enables high performance animations declared on the server and run on the client. As a follow up to my previous thread A libr...
New
type1fool
WebAuthnLiveComponent WebAuthnComponents See this post about renaming the package. Passwordless authentication for Phoenix LiveView app...
New
woylie
Flop is an Elixir library that applies filtering, ordering and pagination parameters to your Ecto queries. offset-based pagination with...
New

Other popular topics Top

minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
AstonJ
Seen any cool LiveView demos, sample apps or examples? Please post them here! :003:
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New

We're in Beta

About us Mission Statement