block by timelyportfolio 2657963ea577afe43b6eeab798b31c67

semiotic in R

Full Screen

Yes, R users can use React as shown in this blog post. This example uses Semiotic from Elijah Meeks. I temporarily built a standalone JS while issue gets resolved by the real experts.

This is a replication of the Semiotic dotplot example. The JavaScript is mostly copied directly from the example except for minor modifications to inject R data.

library(htmltools)
library(reactR)
library(tidyr)

# thanks to https://github.com/emeeks/semiotic/issues/70
#   use unpkg for semiotic
semiotic <- htmlDependency(
  name = "semiotic",
  version = "1.2.4",
  src = c(href = "https://unpkg.com/semiotic/dist"),
  script = "semiotic.min.js"
)

# original data was in wide format
dotwide <- data.frame(
  region = c("Developed regions", "Developing regions", "Northern Africa", "Sub-Saharan Africa", "Latin America and the Caribbean", "Caucasus and Central Asia", "Eastern Asia", "Eastern Asia excluding China", "Southern Asia", "Southern Asia excluding India", "South-eastern Asia", "Western Asia", "Oceania", "World"),
  y1990 = c(7.6, 36.4, 30, 45.5, 22.1, 25.7, 24.5, 11.6, 50.6, 49.3, 27.4, 27.5, 26.3, 33.3),
  y2013 = c(3.4, 22, 13.3, 31.1, 9.2, 14.8, 7.7, 7.5, 29.5, 30.1, 14.4, 13.7, 21.3, 20),
  stringsAsFactors = FALSE
)

# convert to long format in R rather than JavaScript
dotlong <- gather(dotwide, type, value, -region)

dotplot <- tags$script(HTML(babel_transform(
sprintf('
const colors = {
  y1990: "#00a2ce",
  y2013: "#4d430c"
};

const dotRadius = 8;

const baseData = %s

const data = %s;

const lineAnnotations = baseData.map(d => Object.assign({ type: "range" }, d));

function drawRange({ d, rScale, orFrameState }) {
  if (d.type === "range") {
    const start = rScale(d.y1990) - dotRadius;
    const end = rScale(d.y2013) + dotRadius;
    const y = orFrameState.projectedColumns[d.region].middle;
    return (
      <line
        key={`connector-${d.region}`}
        x1={start}
        x2={end}
        y1={y}
        y2={y}
        style={{ stroke: "black", strokeWidth: 2 }}
      />
    );
  }
  return null;
}

const dotplot =
<Semiotic.ORFrame
  title={"Neonatal Mortality Rate by Region"}
  size={[700, 500]}
  data={data}
  rAccessor={d => d.value}
  oAccessor={d => d.region}
  style={(d, i) => ({
    fill: colors[d.type],
    stroke: "white",
    strokeWidth: 1
  })}
  type={{ type: "point", r: dotRadius }}
  projection={"horizontal"}
  axis={{ orient: "bottom", tickFormat: d => `${d}%%` }}
  margin={{ left: 215, top: 50, bottom: 40, right: 10 }}
  oPadding={10}
  svgAnnotationRules={drawRange}
  annotations={lineAnnotations}
  pieceHoverAnnotation={true}
  oLabel={d => (
    <text style={{ textAnchor: "end" }} transform="translate(-15,6)">
      {d}
    </text>
  )}
/>

ReactDOM.render(dotplot, document.body)
',
  jsonlite::toJSON(dotwide, dataframe="rows"),
  jsonlite::toJSON(dotlong, dataframe="rows")
)
)))

browsable(
  tagList(
    dotplot,
    html_dependency_react(offline=FALSE),
    semiotic
  )
)

index.html