Site icon R-bloggers

Baby steps with RSRuby in Rails

[This article was first published on What You're Doing Is Rather Desperate » R, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Plotting and charting libraries for Ruby (on Rails) abound. However, few are sophisticated enough for scientists and many are not actively maintained. Plotting in R, on the other hand, is about as sophisticated as it comes.

Can we bridge Ruby and R? Yes we can, thanks to Alex Gutteridge’s RSRuby. The next logical question: how to plot data using RSRuby in your shiny new Rails application?
Update Jul 22: recently, the code in this post has stopped working for me (unwanted X windows pop up, stack smashing errors) – so use at your discretion or not at all!

First, thanks to Peter Lane over at Ruby for Scientific Research, a relatively-new blog with some excellent introductory RSRuby articles. Thanks also to Alex for providing RSRuby.

  1. Install RSRuby
  2. My OS is Ubuntu 9.04 with rubygems 1.3.3, installed from source and Rails 2.3.2. This works for me:

    sudo gem install rsruby -- --with-R-home=/usr/lib/R --with-R-include=/usr/share/R/include
    
  3. Make the RSRuby gem available to Rails
  4. I edited config/environment.rb to include the gem:

    Rails::Initializer.run do |config|
      config.gem 'rsruby'
      # other config options here...
    end
    
  5. Create your Rails application
  6. Let’s call it Plotter. Usual procedure:

    rails Plotter
    cd Plotter
    rake db:create
    

    We won’t use the database (default sqlite3) in this example, but you may use it later on.

  7. Tell the application about R_HOME
  8. RSRuby will fail unless the environment variable R_HOME is set. To tell Plotter that R_HOME is /usr/lib/R, I put this in the file app/helpers/application_helper.rb:

    module ApplicationHelper
    # set R_HOME if not set
      if ENV['R_HOME'].nil?
        ENV['R_HOME'] = "/usr/lib/R"
      end
    end
    
  9. Make an instance of RSRuby available to all controllers
  10. RSRuby works by providing an instance of an “R object”, on which you call R functions as methods. I provided the object by editing app/controllers/application_controller.rb to include a method named InitR:

    class ApplicationController < ActionController::Base
    # Make R instance available to all
      def InitR
        @r = RSRuby.instance
        return @r
      end
    end
    
  11. Create a sample controller and view
  12. For testing purposes, I created a controller named Home with a single view named index:

    ./script/generate controller Home index
    rm public/index.html
    

    I edited config/routes.rb so as the root of the application is the index view for the home controller:

    ActionController::Routing::Routes.draw do |map|
      map.root      :controller => "home"  #default view is app/views/home/index.html.erb
      map.connect  ':controller/:action/:id'
      map.connect  ':controller/:action/:id.:format'
    end
    

    Now we can get to work on the file app/controllers/home_controller.rb. I wrote a sample method, show_image to plot a histogram using R via RSRuby:

      def show_image
      # next 6 lines use R to plot a histogram
        @r = InitR()
        @d = @r.rnorm(1000)
        @l = @r.range(-4,4,@d)
        @r.png "/tmp/plot.png"
        @r.par(:bg => "cornsilk")
        @r.hist(@d, :range => @l, :col => "lavender", :main => "My Plot")
        @r.eval_R("dev.off()")  #required for png output
        # then read the png file and deliver it to the browser
        @g = File.open("/tmp/plot.png", "rb") {|@f| @f.read}
        send_data @g, :type=>"image/png", :disposition=>'inline'
      end
    

    Not the prettiest code, but you get the idea. Obviously the owner of the HTTP daemon (www-data on Ubuntu) must have write permission to the location of the PNG file; /tmp in this case.

  13. Create the view
  14. All that remains is to edit app/views/home/index.html.erb so as it displays the image:

    <h1>Home#index</h1>
    <p>Find me in app/views/home/index.html.erb</p>
    <%= image_tag(url_for(:controller => "home", :action => "show_image")) %>
    

    Which just says “wrap whatever comes out of the method show_image in an IMG SRC tag”.

RSRuby on Rails histogram plot


Fire up your application using “./script/server”, point your browser at http://localhost:3000 and you should see something like the image to the right.

One drawback of this approach is the need to write a file to disk and so have to worry about naming, cleaning up and so on. I have not found a way to make R output plots to stdout or as a base64 string. If you think this is possible, leave a comment.

OK – so now you can get serious, write some generic methods, design a database schema to store data for plotting and so on.


Posted in computing, R, ruby Tagged: cran, rails, rsruby

To leave a comment for the author, please follow the link and comment on their blog: What You're Doing Is Rather Desperate » R.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.