Call matplotlib from R

April 1, 2015
By

(This article was first published on Rcpp Gallery, and kindly contributed to R-bloggers)

Motivation

I often use Python and matplotlib for
exploring measurement data (from e.g. accelerometers), even if I use R for
the actual analysis. The reason is that I like to be able to flexibly zoom
into different parts of the plot using the mouse and this works well for me
with matplotlib. So I decided to try to call matplotlib from R using Rcpp and
Python/C API.

It was surprisingly simple to get it working and I put together a small
R-package Rpyplot. The package seems
to work well on Ubuntu and Windows 7 for my use cases.

A lot of the code is based on the informative Call Python from R through
Rcpp
post in Rcpp gallery. I
decided not use Boost.Python to make compiling on Windows simpler.

This post explains how I implemented the package and hopefully it will also
allow others to expand the package for their needs. If you do implement
additional functionality for Rpyplot I’d appreaciate a pull request on
Github.

Set up

You’ll need to have Python in your path and Python headers and matplotlib
installed (id sudo apt-get install python-dev python-matplotlib in
Ubuntu). In Windows I have used the
Anaconda Python distribution.

The following sets the compiler flags for Ubuntu:

py_cflags <- system("python2.7-config --cflags", intern=TRUE)
Sys.setenv("PKG_CXXFLAGS"=sprintf("%s %s", Sys.getenv("PKG_CXXFLAGS"), py_cflags))
py_ldflags <- system("python2.7-config --ldflags", intern=TRUE)
Sys.setenv("PKG_LIBS"=sprintf("%s", py_ldflags))

You can have a look at the Makevars.win in Rpyplot-package to see how to set the flags for Windows.

Calling Python from R

Initializing

The snippet below contains code required to initialize Python and imports pyplot from matplotlib and pyrun function that can be used to call Python from R. All code executed with pyrun (or PyRun_SimpleString in C++) runs Python source code in the scope of __main__ module.

#include 
#include 
#include 
#ifndef WIN32
#include 
#endif

using namespace Rcpp;

//Run Python commands from R
//[[Rcpp::export]]
void pyrun(std::string command) {
    PyRun_SimpleString(command.c_str());
}

//You need to call this first
//[[Rcpp::export]]
void initialize_python() {
#ifndef WIN32
   dlopen("libpython2.7.so", RTLD_LAZY |RTLD_GLOBAL); //Required to import matplotlib
#endif
    Py_Initialize();
    pyrun("import matplotlib");
    //pyrun("matplotlib.use('Qt4Agg')");
    pyrun("import matplotlib.pyplot as plt");
}

//Call after you're done
//[[Rcpp::export]]
void finalize_python() {
    Py_Finalize();
}

Copying data

It is not enough to be able to just run Python commands from strings, but we also need to pass data from R to Python. The numvec_to_python function below copies a numeric vector from R to a Python list and adds it to Python’s __main__ module. It is then accessible to Python commands executed with pyrun.

#include 
#include 
#include n
using namespace Rcpp;

//Convert NumericVector to Python List
PyObject* numvec_to_list(NumericVector x) {
    int n = x.length();
    PyObject *xpy = PyList_New(n); //Make new list
    PyObject *f;
    
    for (int i=0; i<n; i++) {
      f = PyFloat_FromDouble(x[i]);
      PyList_SetItem(xpy, i, f); //Fill list from NumericVector
    }   
    return(xpy);
}

//Copy a numeric vector from R to Python
//[[Rcpp::export]]
void numvec_to_python(std::string name, NumericVector x) {
    PyObject *xpy = numvec_to_list(x);
    PyObject *m = PyImport_AddModule("__main__");
    PyObject *main = PyModule_GetDict(m); //Get the locals dictionary of __main__ module
    PyDict_SetItemString(main, name.c_str(), xpy); //Add variable to that dictionary
}

Plotting

Using the functions defined above makes calling matplotlib simple. First you
will need to copy a vector to Python and then you are able to plot it running
Python commands using pyrun. You can see how different plots are created in
Rpyplot by looking at Plot.R. The implemenation
of pycontourf function also shows how to copy an R matrix to Python and
convert it to a NumPy array.

Here is a small example on how the above functions can be used to create two
line plots. You’ll need to call plt.show() in order to open the plot, but
when you do the program will hang until all opened figure windows are closed
so make sure to only call it at the end of a script.

x <- seq(0, 2*pi, length = 100)
sx <- sin(x)
cx <- cos(x)

initialize_python()
#Copy variables to Python
numvec_to_python("x", x) 
numvec_to_python("sx", sx)
numvec_to_python("cx", cx)
#Create plots
pyrun("plt.plot(x, sx)")
pyrun("plt.plot(x, cx, '--r', linewidth=2) ")
#pyrun("plt.show()") #Uncomment this line to show the plot

To leave a comment for the author, please follow the link and comment on their blog: Rcpp Gallery.

R-bloggers.com offers daily e-mail updates about R news and tutorials on topics such as: Data science, Big Data, R jobs, visualization (ggplot2, Boxplots, maps, animation), programming (RStudio, Sweave, LaTeX, SQL, Eclipse, git, hadoop, Web Scraping) statistics (regression, PCA, time series, trading) and more...



If you got this far, why not subscribe for updates from the site? Choose your flavor: e-mail, twitter, RSS, or facebook...

Comments are closed.

Sponsors

Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)