Skip to content

Instantly share code, notes, and snippets.

@timelyportfolio
Last active November 30, 2017 02:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save timelyportfolio/2657963ea577afe43b6eeab798b31c67 to your computer and use it in GitHub Desktop.
Save timelyportfolio/2657963ea577afe43b6eeab798b31c67 to your computer and use it in GitHub Desktop.
semiotic in R
license: mit

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
  )
)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<script src="//unpkg.com/react/umd/react.production.min.js"></script>
<script src="//unpkg.com/react-dom/umd/react-dom.production.min.js"></script>
<script src="//unpkg.com/semiotic/dist/semiotic.min.js"></script>
</head>
<body style="background-color:white;">
<script>"use strict";
var colors = {
y1990: "#00a2ce",
y2013: "#4d430c"
};
var dotRadius = 8;
var baseData = [{ "region": "Developed regions", "y1990": 7.6, "y2013": 3.4 }, { "region": "Developing regions", "y1990": 36.4, "y2013": 22 }, { "region": "Northern Africa", "y1990": 30, "y2013": 13.3 }, { "region": "Sub-Saharan Africa", "y1990": 45.5, "y2013": 31.1 }, { "region": "Latin America and the Caribbean", "y1990": 22.1, "y2013": 9.2 }, { "region": "Caucasus and Central Asia", "y1990": 25.7, "y2013": 14.8 }, { "region": "Eastern Asia", "y1990": 24.5, "y2013": 7.7 }, { "region": "Eastern Asia excluding China", "y1990": 11.6, "y2013": 7.5 }, { "region": "Southern Asia", "y1990": 50.6, "y2013": 29.5 }, { "region": "Southern Asia excluding India", "y1990": 49.3, "y2013": 30.1 }, { "region": "South-eastern Asia", "y1990": 27.4, "y2013": 14.4 }, { "region": "Western Asia", "y1990": 27.5, "y2013": 13.7 }, { "region": "Oceania", "y1990": 26.3, "y2013": 21.3 }, { "region": "World", "y1990": 33.3, "y2013": 20 }];
var data = [{ "region": "Developed regions", "type": "y1990", "value": 7.6 }, { "region": "Developing regions", "type": "y1990", "value": 36.4 }, { "region": "Northern Africa", "type": "y1990", "value": 30 }, { "region": "Sub-Saharan Africa", "type": "y1990", "value": 45.5 }, { "region": "Latin America and the Caribbean", "type": "y1990", "value": 22.1 }, { "region": "Caucasus and Central Asia", "type": "y1990", "value": 25.7 }, { "region": "Eastern Asia", "type": "y1990", "value": 24.5 }, { "region": "Eastern Asia excluding China", "type": "y1990", "value": 11.6 }, { "region": "Southern Asia", "type": "y1990", "value": 50.6 }, { "region": "Southern Asia excluding India", "type": "y1990", "value": 49.3 }, { "region": "South-eastern Asia", "type": "y1990", "value": 27.4 }, { "region": "Western Asia", "type": "y1990", "value": 27.5 }, { "region": "Oceania", "type": "y1990", "value": 26.3 }, { "region": "World", "type": "y1990", "value": 33.3 }, { "region": "Developed regions", "type": "y2013", "value": 3.4 }, { "region": "Developing regions", "type": "y2013", "value": 22 }, { "region": "Northern Africa", "type": "y2013", "value": 13.3 }, { "region": "Sub-Saharan Africa", "type": "y2013", "value": 31.1 }, { "region": "Latin America and the Caribbean", "type": "y2013", "value": 9.2 }, { "region": "Caucasus and Central Asia", "type": "y2013", "value": 14.8 }, { "region": "Eastern Asia", "type": "y2013", "value": 7.7 }, { "region": "Eastern Asia excluding China", "type": "y2013", "value": 7.5 }, { "region": "Southern Asia", "type": "y2013", "value": 29.5 }, { "region": "Southern Asia excluding India", "type": "y2013", "value": 30.1 }, { "region": "South-eastern Asia", "type": "y2013", "value": 14.4 }, { "region": "Western Asia", "type": "y2013", "value": 13.7 }, { "region": "Oceania", "type": "y2013", "value": 21.3 }, { "region": "World", "type": "y2013", "value": 20 }];
var lineAnnotations = baseData.map(function (d) {
return Object.assign({ type: "range" }, d);
});
function drawRange(_ref) {
var d = _ref.d,
rScale = _ref.rScale,
orFrameState = _ref.orFrameState;
if (d.type === "range") {
var start = rScale(d.y1990) - dotRadius;
var end = rScale(d.y2013) + dotRadius;
var y = orFrameState.projectedColumns[d.region].middle;
return React.createElement("line", {
key: "connector-" + d.region,
x1: start,
x2: end,
y1: y,
y2: y,
style: { stroke: "black", strokeWidth: 2 }
});
}
return null;
}
var dotplot = React.createElement(Semiotic.ORFrame, {
title: "Neonatal Mortality Rate by Region",
size: [700, 500],
data: data,
rAccessor: function rAccessor(d) {
return d.value;
},
oAccessor: function oAccessor(d) {
return d.region;
},
style: function style(d, i) {
return {
fill: colors[d.type],
stroke: "white",
strokeWidth: 1
};
},
type: { type: "point", r: dotRadius },
projection: "horizontal",
axis: { orient: "bottom", tickFormat: function tickFormat(d) {
return d + "%";
} },
margin: { left: 215, top: 50, bottom: 40, right: 10 },
oPadding: 10,
svgAnnotationRules: drawRange,
annotations: lineAnnotations,
pieceHoverAnnotation: true,
oLabel: function oLabel(d) {
return React.createElement(
"text",
{ style: { textAnchor: "end" }, transform: "translate(-15,6)" },
d
);
}
});
ReactDOM.render(dotplot, document.body);</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment