RStudio recently announced the reticulate
package, which is designed to help R users inter-operate with Python code. I was immediately excited by this announcement. In a past life, I worked with a team at the National Renewable Energy Lab (NREL) on vehicle simulations. Their models could predict MPG for vehicles based on driving routes. At the time, I had wanted to build a web app that would allow users to predict MPG for different vehicles based on their daily commutes. Unfortunately the model was written in Python, but my web application experience was limited to Shiny. I didn’t want to rewrite the model in R, nor did I have time to learn a Pythonic web framework. Nothing came of the idea…until today*!
Using reticulate
, I was able to easily build a Shiny application that used my colleague’s Python code. I also used Python’s Google Maps API client. While R packages exist to work with Google Maps, the Python client is maintained by Google and is simple to access with reticulate
.
Checkout the live application and source code.
This post covers a few details and tips for using reticulate
, and creating reticulated Shiny apps.
Getting Started
To use reticulate
you’ll need to setup Python and any Python dependencies required by your project. We recommend using virtualenv
and pip
, which are well documented for newcomers.
Once your Python environment is setup, you’ll need to tell the reticulate
package to use the environment. reticulate
provides the helper functions: use_virtualenv
and use_conda
. These functions should be called before any other reticulate
functions are used. For example, I included the following lines at the top of my app.R
file:
library(reticulate)
use_virtualenv('/path/to/myhybrid-project', required = TRUE)
Once your environment is setup, there are two methods for interacting with reticulate
code.
Method 1: “Sourcing”
In my case, the Python code my colleagues developed was available in a single Python file. The file consisted of a number of Python functions. To use those functions, I ran source_python('../subdir/with/python-model.py')
.
Once sourced, I was able to call the Python functions directly as R functions. For example, one of the functions defined in my Python file was sim_drive
. The function signature in Python looks like:
def sim_drive( cyc , veh ):
cyc
and veh
are both Python dictionaries. The function normally returns a complex Python dictionary containing numeric values as well as numpy arrays. In my R code, I can invoke sim_drive
as an R function:
results <- sim_drice(cyc, veh)
In my case, cyc
and veh
are R data frames and results
will be an R list. reticulate
handles all of the conversions between R and Python automatically. (This worked the first time I tried it; I was literally giddy!).
If your Python file doesn’t contain functions, but also creates objects, use py_run_file
instead of source_python
and then access the Python objects using py$object
.
Method 2: “Importing”
The second method for writing reticulated code is to import Python objects and write R code that uses those references. This method is helpful if you don’t have existing Python files, but instead want to access Python classes or methods.
For my app, I wanted to make use of the Google Maps Python client maintained by Google. The Google help documentation provides sample Python code to query the Directions API:
import googlemaps
import os
from datetime import datetime
gmaps = googlemaps.Client(key=os.environ['DIRECTIONS_API_KEY'])
def get_route(start, end):
route = gmaps.directions(start,
end,
mode = "driving",
departure_time = datetime.now())
return(route)
Using reticulate, I was able to write similar R code that utilized the same Python objects:
googlemaps <- import('googlemaps')
gmaps <- googlemaps$Client(key = Sys.getenv('DIRECTIONS_API_KEY'))
get_route <- function(start, end) {
route <- gmaps$directions(
start,
end,
mode = "driving",
departure_time = Sys.time())
return(route)
}
I was able to swap some of the Python components with R code; for example I used Sys.time
and Sys.getenv
in place of datetime
and os
. reticulate
’s flexibility lets you interweave R and Python code.
The resulting routes
object is a complex nested list. I opted to use purrr
to process this list, but if you were familiar with Python tools, you could continue to write reticulated code. reticulate
enables you to pick the pieces from each language that you like best. The remainder of the application logic is written in R, including the use of SMA
for smoothing and a fair subset of the tidyverse
for tidying and plotting data. I’d be remiss if I didn’t include a brief shout-out to the shinymaterial
package for providing an appealing and easy-to-use shiny theme.
Deployment
Like any Shiny application, a reticulated Shiny app has to be deployed in order for others to leverage the app. Reticulated Shiny apps can be deployed like regular Shiny apps, but take care to ensure that the deployment server has the same Python environment.
Parting Thoughts
reticulate
helped me accomplish a task that I had been day dreaming about for years. You don’t need to be a Python expert, but you do get many of the benefits.
The reticulate
website explains that the name of the package comes from the interweaving color pattern found on reticulated pythons. I found interweaving Python and R to create reticulated R code powerful and enjoyable. I can’t wait to see more examples of this new breed of code!
*Disclaimer
Access to NREL’s FASTSim model used in this demo is available here. The Shiny application was developed independently by RStudio as a demo using the freely available FASTSim model. The application was not written in conjunction with the National Renewable Energy Lab (NREL), nor is the application endorsed by NREL. The results presented in the application are not to be used for accurate vehicle comparisons. RStudio is NOT RESPONSIBLE for the accuracy or reliability of any results presented in the application.
You may leave a comment below or discuss the post in the forum community.rstudio.com.