react

Build Your Own React-based htmlwidget

Making of nivocal

nivocal was built to be a working package, but while I was at it I wanted to record each step in the creation journey as a reference for future authors of reactR-based htmlwidgets. For reference, the package in its initial working state required less than 30 minutes of effort. I never left my RStudio window, and I only had to write 1.5 lines of JavaScript.

One Time on the Internet I Found …

There are some amazing React comoponents out there. If one day on the Internet, you find something you like then it can be ready to use in R in less than an hour (hopefully shorter if you read this document). Take for example the @nivo set of components. I’d like to use the Github-style calendar.

screenshot of nivo calendar

Starting the Package

usethis allows us to create a package in one line of code. Let’s begin our journey here.

usethis::create_package("nivocal")

screencast of creating package with use this

Scaffolding

Once we have a package, we’ll open it up and then build a scaffold. Sometimes finding the npmPkgs argument can be a little tricky. Usually, the best clues are in the docs, but we can also use unpkg.com–the CRAN of Node JavaScript–for some help. End the url with / to see the contents of the package and find the most recent version. For the calender, we do https://unpkg.com/@nivo/calendar/. Remember the /. Try https://unpkg.com/@nivo/calendar to see the difference.

scaffoldReactWidget(
  "nivocal",
  npmPkgs = c("@nivo/calendar" = "0.52.1")
)

screencast of scaffolding the widget

Now we have all the files we need for a working htmlwidget but unfortunately not working in the way we want.

1.5 Lines of JavaScript and Build

In the JavaScript, we will need to import the module we want to use. For nivocal we want ResponsiveCalendar. import in JavaScript is very similar to library() in R.

import { ResponsiveCalendar } from '@nivo/calendar'

The JavaScript build toolchain can get complicated, but fortunately reactR takes care of much of this for us. I hate to tell you, but you will need to install node and yarn. I promise this is not hard or scary though. Once you have both installed, we will build/webpack our JavaScript in the RStudio terminal or other terminal/console.

yarn install
yarn run webpack

screencast of building the JavaScript

The built JavaScript will be copied into the /inst/htmlwidgets directory ready for use in our R htmlwidget.

Build R Package

We have a couple more things to do on the R side. For now, let’s see if the package builds. In RStudio, we can CTRL + Shift + B or

devtools::document()
devtools::install(quick = TRUE)

screencast of building the R package

If all goes well, then our package is working, but as I said just not quite in the way we want.

Add Some Arguments

Now we need a way to go from R to JavaScript. We’ll add arguments for the data, from, and to component props in our R function.

screencast of add R function arguments

Change the Tag

The scaffold uses div, but we want to use the ResponsiveCalendar component. React components are always capitalized.

screencast of change tag to component

Add More Props/options and Do Some R Work

There are a lot of other options for the calendar. For a well-built R package, I think each of these should be dcoumented arguments, but for now we’ll use ... to pass other options from R to JavaScript.

data, from, and to are required for the calendar component. Eventually, we want to accept various forms of data from the user, but for now we will assume the user provides a data.frame with two columns day and value. htmlwidgets communicate data.frames as an array of arrays but ResponsiveCalendar wants the equivalent of dataframe = "rows" in jsonlite::toJSON(). We’ll use mapply to do this, but as described in the data transformation article we have other methods to achieve this. The most common form – using JavaScript HTMLWidgets.dataframeToD3() – does not currently work well with reactR-based htmlwidgets.

Without from and to, the calendar will not render, so let’s assume the user wants from to be the first row of the data and to to be the last row.

screencast of use ellipsis for other options and munge arguments

It’s Working

Now we have a working htmlwidget. Build the package with CTRL+Shift+B or

devtools::document()
devtools::install(quick = TRUE)

Give it some data and see an interactive calendar.

library(nivocal)

# fake data of 500 records/days starting 2017-03-15
df <- data.frame(
  day = seq.Date(
    from = as.Date("2017-03-15"),
    length.out = 500,
    by = "days"
  ),
  value = round(runif(500)*1000, 0)
)

nivocal(df)

screencast of working package widget

Customize

Remember we added ... for further customization. Let’s see how this works.

library(nivocal)

# fake data of 500 records/days starting 2017-03-15
df <- data.frame(
  day = seq.Date(
    from = as.Date("2017-03-15"),
    length.out = 500,
    by = "days"
  ),
  value = round(runif(500)*1000, 0)
)

nivocal(
  df,
  direction = "vertical",
  colors = RColorBrewer::brewer.pal(n=9, "Blues")
)

screencast of more customization

More Resources

Even though all of this is fairly new, we have tried to offer examples and resources to ease the learning curve. The react-R Github organization is intended to be a friendly central location for all things R + React. Please join in the fun.

Vue

We’d like to do the same for Vue. Please let us know if you have interest. vueR would be a good starting point.

React in R

This post is courtesy of Displayr who have generously offered to sponsor a series of independently authored posts about interactive visualization with R and JavaScript. Thank you so much Displayr for this opportunity.

crossposted at buildingwidgets and jsinr

In this post, we will pivot from iterative tree visualization to using the very popular JavaScript thing called React in R. With some assistance from the helper R package reactR, we will learn to incorporate Reactcomponents in our output and make a Semiotic chart from R data. I would recommend reading and working through the React tutorial before beginning this post, but I bet you can follow along even if you ignore this recommendation.

reactR

Most React projects require at least two things:

  1. React and ReactDOM JavaScript dependencies
  2. babel compiler to convert JSX and/or ES2015 (and beyond) to plain old JavaScript.

To ease this burden for the R user of React, I built the package reactRwhich allows us to accomplish both of the above requirements.reactR::html_dependency_react() provides up-to-date JavaScript dependencies for React and ReactDOM for use in Rmarkdown, Shiny, or other html projects. reactR::babel_transform() uses the V8 package to compile your JSX and ES2015 (and beyond) all within your R session.

Pattern for React and R

We will use the following generic pattern as we attempt to combine React with R.

library(htmltools)
library(reactR)

tagList(
  # add JavaScript dependencies React and ReactDOM
  reactR::html_dependency_react(),
  tags$div(...),
  tags$script(HTML(
    # babel_transform is only necessary if we plan to use
    #   ES2015 and/or JSX.  Most of the React examples out
    #   there will use one or both.
    reactR::babel_transform(
      sprintf(...)
    )
  ))
)

First Example

Let’s try it with a real example similar to the React Hello World! example. In our example, we will use React to render a heading h1 along with some text.

library(htmltools)
library(reactR)

tagList(
  reactR::html_dependency_react(),
  tags$div(id = "example"),
  tags$script(HTML(
    babel_transform(
"
ReactDOM.render(
  <div>
    <h1>React + R = BFF</h1>
    <p>This should probably be airbrushed Spring Break style
    on a t-shirt or license plate.
    </p>
  </div>,
  document.getElementById('example')
)
"
    )
  ))
)
reactR_example1.gif

Often, quotes " and ' are the most frustrating part about combining JavaScript and R. I tend to use " for R and ' for JavaScript.

Office React Components in R

I know that most R purists have eliminated Microsoft Office from their workflows, but we can bring a little bit of the “good” from Microsoft Office with the very well-built and helpful Office UI Fabric components for React. And yes you can use these with Shiny.

library(htmltools)
library(reactR)

fabric <- htmlDependency(
  name = "office-fabric-ui-react",
  version = "5.23.0",
  src = c(href="https://unpkg.com/office-ui-fabric-react/dist"),
  script = "office-ui-fabric-react.js",
  stylesheet = "css/fabric.min.css"
)

browsable(
  tagList(
    html_dependency_react(offline=FALSE),
    fabric,
    tags$div(id="pivot-example"),
    tags$script(HTML(babel_transform(
"
class PivotBasicExample extends React.Component {
  render() {
    return (
      <div>
        <Fabric.Pivot>
          <Fabric.PivotItem linkText='My Files'>
            <Fabric.Label>Pivot #1</Fabric.Label>
          </Fabric.PivotItem>
          <Fabric.PivotItem linkText='Recent'>
            <Fabric.Label>Pivot #2</Fabric.Label>
          </Fabric.PivotItem>
          <Fabric.PivotItem linkText='Shared with me'>
            <Fabric.Label>Pivot #3</Fabric.Label>
          </Fabric.PivotItem>
        </Fabric.Pivot>
      </div>
    );
  }
}
ReactDOM.render(<PivotBasicExample />, document.querySelector('#pivot-example'));
"
    )))
  )
)
office-ui-fabric React component from R

office-ui-fabric React component from R

Now you might have noticed that the RStudio Viewer showed up as blank. This seems to be an issue with non-local JavaScript dependencies in RStudio Viewer. I think the only way around this problem is to store the dependencies locally. A package housing these dependencies similar to reactR is probably the best option.

antd React Components to Step Through lm

antd is another set of very nice React components. Let’s walk through a lm from R using the step-through antd component.

Now we are getting much closer to our ultimate objective of using R data with React with a synergistic result.

Visualizations with Semiotic

Elijah Meeks has very generously contributed the React-based visualization library Semiotic. We will recreate one of the examples, but we’ll do the data part in R. Data from R and interactive vis from JavaScript hopefully will continue to become a popular and common workflow.

An htmlwidget for Semiotic would offer the ideal method of full integration, but I have not yet determined a good pattern for creating React-based htmlwidgets. Please let me know if you have thoughts or would like to collaborate towards achieving this goal.

Next Steps

An obvious next step would be integrating React with Shiny, and as I said before, this is possible. Also, there is another very popular JavaScript framework called Vue that I actually think is even easier to integrate with R. In the next post, we’ll demonstrate R + Vue.