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.

Visualizing Trees | Partition + Sankey

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 jsinr.me and Medium

This will be the last post in our iterations in visualizing trees. In the next post, we’ll move on to how we can use the very popular React in R.

Our first post yielded a sankeytree concoction.

sankey + tree

sankey + tree

Then our second post made a more compact parttree.

Although the parttree is more compact, we can compress even further by stacking our link paths to reflect the leaf details and eliminating the leaf nodes. Then, we can blend in some interactivity to help the user process the visualization and examine the data.

Eliminating Repetition

At the leaf level of our parttree, the repetition of "Yes" and "No" could interfere with our ability to compare survival at each level.

partsankey_partree_repetition.png

Let’s see what happens if we instead convey the survival information in our link paths that connect the nodes. This is similar to a stacked bar or streamgraph. To accomplish this, we will use d3.stack().

Interactivity

We save some space, but a user might get confused. For example, the "Yes" does not flow through the nodes. Some interactivity might help clear up the confusion.

partition + sankey (interactive)

partition + sankey (interactive)

Next

Iterating through our last three posts demonstrates how creative blending can result in unique representations of tree hierarchies from R or JavaScript. We’ll stop here with our iteration, but we could easily transform this or other visualizations into htmlwidgets for even easier consumption by R users.

Much of the recent innovation in JavaScript visualization has happened in the newest frameworks, such as React and Vue. We’ll see in the next couple of posts how to use these new frameworks in R.

Visualizing Trees | Partition + Tree

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 Medium

Before I start on the second post on the series, I wanted to make sure all my R readers knew that the charts in this post are created in R using htmltools. Also, each chart should have a link to reproducible code.

In our first attempt at improving hierarchical visualization, we combined d3.tree() with d3-sankey. Our sankeytree concoction allows us to convey size or flow from one level to the next while maintaining some sense of the tree, but the sankeytree still suffers from the universal constant node size (height and width).

We are left with extra wasted space that possibly distracts from the message of the visualization. In this post we will see if we can eliminate some of this space with d3.partition() assisted by d3.treemap(). Let’s call this one parttree.

d3.partition()

Partition, or icicle, visualizations fill space much like a diced treemap or side-by-side stacked bar chart. The visualizations are commonly used in debugging and programming optimization. In this context, they are called flame graphs.

flame graph from Chrome debugger

flame graph from Chrome debugger

Since we are trying to eliminate some of the wasted space from our sankeytree, let’s see if we might be able to leverage the “space-filling” d3.partition(). For consistency, let’s continue to use the Titanic dataset from R and create a partition.

While d3.partition() efficiently fills the space, these charts in this context do not reveal the hierarchical nature of the underlying data as much as I would like. Also, in my opinion, the above chart is not very inviting or “fun”.

What if we start with d3.partition() and then use a node size smaller than the partition-assigned size? Then, we might have some space to draw links like a d3.tree() or d3-sankey. Seeing is believing, so let’s make the suggested adjustment to the partitioned Titanic and then animate the transformation.

I consider this good progress, and our new parttree imparts a sense of hierarchy with an efficient and compact portrayal of size and flow. I should note that we sprinkled in some assistance from d3.stack() and d3.treemap(). However, the straight angled links might be a little rigid. This can be solved with help from d3.linkHorizontal.

Finishing Touches

A little curve in our links might be nice. However, just a line with width defined by stroke-width can limit us in ways we might discuss in future posts, so let’s define a path with four points to draw our link.

Just imagine if we add proper labels, good color, and interactivity.

Next

If we like our new creation, then next steps will be to create a more formal d3 layout and then build a reusable chart based on the layout. As mentioned in the post, drawing the links as a path with four points instead of a line with two points will allow us the ability to add even more encoding and information in our links. In the next post, we will explore what we can do with our new powers.

Visualizing Trees | Sankey + Tree

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 JSinR and Medium

d3 provides a helpful suite of layouts (cluster, tree, treemap, pack, and partition) for visualizing tree networks or hierarchies. In addition, we have the d3-sankey plugin for a Sankey diagram as another mechanism for presenting tree data. Approaching the layout decision as a mutually exclusive proposition means that we lose many of the benefits from alternative layouts. However, incorporating our favorite features from more than one layout can provide us with a more effective means of interactive visualization of the very common tree data structure. Let’s explore the specific combination of d3.tree() with d3-sankey.

d3.tree()

In 1981 Edward Reingold and John Tilford published

Reingold, Edward M., and John S. Tilford. “Tidier drawings of trees.” IEEE Transactions on Software Engineering 2 (1981): 223–228.

which gives us the Reingold-Tilford algorithm, the basis of d3.tree(). Here is a quick unadorned example of the output of d3.tree() with the R dataset Titanic using networkD3 diagonalNetwork() for convenience.

d3-sankey

In contrast, d3-sankey helps overcome the two shortcomings of d3.tree() mentioned above. In the next example, we use the same data in a Sankey diagram. We can see that node sizes are no longer uniform and links reveal size.

So we “solved” the d3.tree() shortcomings, but when we represent as a Sankey diagram, I think we lose the fact that the underlying data is a tree. This “loss of insight” becomes more obvious when we try to think of ways to collapse a Sankey diagram.

sankeytree

Let’s explore how we might blend d3-sankey with d3.tree() and call our concoction a sankeytree. We can start with d3.tree() and then draw our nodes and links to be Sankey-like with height proportional to size. Displayr has helped us here with their open source R htmlwidget rhtmlSankeyTree. Below is an example.

While not perfect, the height of the flow from parent to child now indicates size of the child in relation to size of the parent. This combined layout still suffers from the constant node height constraint of the Reingold-Tilford algorithm in d3.tree() and is much less compact than d3-sankey. However, with pan, zoom, collapse, and expand interactivity, we can help overcome the loss of compactness from wasted space. This interactivity also aids user intuition around the tree structure. Here is an example.

sankeytree on Titanic with interactivity

sankeytree on Titanic with interactivity

Using sankeytree with Recursive Partitioning

Decision tree learning results in tree structures that offer a more “real-life” opportunity for sankeytree. We can quickly explore a very basic recursive partitioning classification on the Titanic data that we have used throughout the post. To do it with no coding, we’ll use Displayr (live example).

Next Steps

Interactivity improves the experience and intuition with sankeytree, but the wasted space bothers me. In future posts in the series, we will explore more combinations of sankey features with d3 layouts and extensions to eliminate the wasted space and improve the user experience.

JavaScript in R Series of Posts

One of the very fine folks at Displayr asked if I might be interested in writing a series of posts extending my 2015 htmlwidget/week project.  I said yes as long as I have "creative" license (never thought I would be requesting that in my lifetime), so away we go.  I plan to narrowly focus on combining JavaScript with R for visualization and data science.  The posts will appear on this site along with crossposts at my new site JSinR and on Medium to satisfy your viewing preference.

For those interested in workflow, the site is built Using RStudio/Yihui Xie’s blogdown package. The package perfectly illustrates the power of combination blending R, Rmarkdown, markdown, and Go. Netlify deploys the static site with every push to Github. Although this might sound difficult to the R user, I promise blogdown and Netlify makes all of this straightforward. Please let me know if I can help.

Thanks so much to Displayr for sponsoring the first set of posts.