Skip to content

Instantly share code, notes, and snippets.

@timelyportfolio
Last active December 19, 2015 19:08
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/6003605 to your computer and use it in GitHub Desktop.
Save timelyportfolio/6003605 to your computer and use it in GitHub Desktop.
rCharts F1

This is a rCharts recreation of the Formula 1 Points Sankey Diagram in this fine post. See this post for more details on how to make d3.js Sankey Diagrams in R with rCharts.

#another one from Tony Hirst
#post at http://blog.ouseful.info/2012/05/24/f1-championship-points-as-a-d3-js-powered-sankey-diagram/
#data at https://views.scraperwiki.com/run/ergast_championship_nodelist/?
#get source from original example
#this is a JSON, so will need to translate
#expect most data to come straight from R
#in form of source, target, value
links <- matrix(unlist(
rjson::fromJSON(
file = "https://views.scraperwiki.com/run/ergast_championship_nodelist/?"
)$links
),ncol = 3, byrow = TRUE)
nodes <- unlist(
rjson::fromJSON(
file = "https://views.scraperwiki.com/run/ergast_championship_nodelist/?"
)$nodes
)
#nodes are 2 columns but in vector form
#just get the name and ignore id
nodes <- nodes[seq(1,length(nodes),by=2)]
#convert to data.frame so souce and target can be character and value numeric
links <- data.frame(links)
colnames(links) <- c("source", "target", "value")
links$source <- sapply(links$source, FUN = function(x) {return(as.character(nodes[x+1]))}) #x+1 since js starts at 0
links$target <- sapply(links$target, FUN = function(x) {return(nodes[x+1])}) #x+1 since js starts at 0
#now we finally have the data in the form we need
sankeyPlot <- rCharts$new()
sankeyPlot$setLib('.')
sankeyPlot$setTemplate(script = "layouts/chart.html")
sankeyPlot$set(
data = links,
nodeWidth = 15,
nodePadding = 10,
layout = 32,
width = 700,
height = 400,
units = "points"
)
sankeyPlot
<!doctype HTML>
<meta charset = 'utf-8'>
<html>
<head>
<link rel='stylesheet' href="http://netdna.bootstrapcdn.com/bootswatch/2.3.1/cosmo/bootstrap.min.css">
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-responsive.min.css" >
<link rel='stylesheet' href="http://twitter.github.io/bootstrap/assets/js/google-code-prettify/prettify.css">
<link rel='stylesheet' href="http://aozora.github.io/bootplus/assets/css/docs.css">
<link rel='stylesheet' href='http://timelyportfolio.github.io/rCharts_d3_sankey/css/sankey.css'>
<script src='http://d3js.org/d3.v3.min.js' type='text/javascript'></script>
<script src='http://timelyportfolio.github.io/rCharts_d3_sankey/js/sankey.js' type='text/javascript'></script>
<style>
.rChart {
display: block
margin: auto auto;
width: 100%;
height: 400px;
}
/*
body {
margin-top: 60px;
}
*/
</style>
</head>
<body>
<div class='container'>
<div class='row'>
<div class='span8'>
<div class="bs-docs-example">
<div id='chart2544fc8157a' class='rChart nvd3Plot rCharts_d3_sankey'></div>
<br/>
<pre><code class='r'>#another one from Tony Hirst
#post at http://blog.ouseful.info/2012/05/24/f1-championship-points-as-a-d3-js-powered-sankey-diagram/
#data at https://views.scraperwiki.com/run/ergast_championship_nodelist/?
#get source from original example
#this is a JSON, so will need to translate
#expect most data to come straight from R
#in form of source, target, value
links &lt;- matrix(unlist(
rjson::fromJSON(
file = &quot;https://views.scraperwiki.com/run/ergast_championship_nodelist/?&quot;
)$links
),ncol = 3, byrow = TRUE)
nodes &lt;- unlist(
rjson::fromJSON(
file = &quot;https://views.scraperwiki.com/run/ergast_championship_nodelist/?&quot;
)$nodes
)
#nodes are 2 columns but in vector form
#just get the name and ignore id
nodes &lt;- nodes[seq(1,length(nodes),by=2)]
#convert to data.frame so souce and target can be character and value numeric
links &lt;- data.frame(links)
colnames(links) &lt;- c(&quot;source&quot;, &quot;target&quot;, &quot;value&quot;)
links$source &lt;- sapply(links$source, FUN = function(x) {return(as.character(nodes[x+1]))}) #x+1 since js starts at 0
links$target &lt;- sapply(links$target, FUN = function(x) {return(nodes[x+1])}) #x+1 since js starts at 0
#now we finally have the data in the form we need
sankeyPlot &lt;- rCharts$new()
sankeyPlot$setLib('.')
sankeyPlot$setTemplate(script = &quot;layouts/chart.html&quot;)
sankeyPlot$set(
data = links,
nodeWidth = 15,
nodePadding = 10,
layout = 32,
width = 700,
height = 400,
units = &quot;points&quot;
)
sankeyPlot
</code></pre>
</div>
</div>
</div>
</div>
<!--Attribution:
Mike Bostock https://github.com/d3/d3-plugins/tree/master/sankey
Mike Bostock http://bost.ocks.org/mike/sankey/
-->
<script>
var params = {
"dom": "chart2544fc8157a",
"width": 700,
"height": 400,
"data": {
"source": [ "Australian Grand Prix", "Australian Grand Prix", "Australian Grand Prix", "Australian Grand Prix", "Australian Grand Prix", "Australian Grand Prix", "Australian Grand Prix", "Australian Grand Prix", "Australian Grand Prix", "Australian Grand Prix", "Jenson Button", "Sebastian Vettel", "Lewis Hamilton", "Mark Webber", "Fernando Alonso", "Kamui Kobayashi", "Kimi Rikknen", "Sergio Prez", "Daniel Ricciardo", "Paul di Resta", "Malaysian Grand Prix", "Malaysian Grand Prix", "Malaysian Grand Prix", "Malaysian Grand Prix", "Malaysian Grand Prix", "Malaysian Grand Prix", "Malaysian Grand Prix", "Malaysian Grand Prix", "Malaysian Grand Prix", "Malaysian Grand Prix", "Bruno Senna", "Jean-ric Vergne", "Nico Hlkenberg", "Michael Schumacher", "Chinese Grand Prix", "Chinese Grand Prix", "Chinese Grand Prix", "Chinese Grand Prix", "Chinese Grand Prix", "Chinese Grand Prix", "Chinese Grand Prix", "Chinese Grand Prix", "Chinese Grand Prix", "Chinese Grand Prix", "Nico Rosberg", "Romain Grosjean", "Pastor Maldonado", "Bahrain Grand Prix", "Bahrain Grand Prix", "Bahrain Grand Prix", "Bahrain Grand Prix", "Bahrain Grand Prix", "Bahrain Grand Prix", "Bahrain Grand Prix", "Bahrain Grand Prix", "Bahrain Grand Prix", "Bahrain Grand Prix", "Felipe Massa", "Spanish Grand Prix", "Spanish Grand Prix", "Spanish Grand Prix", "Spanish Grand Prix", "Spanish Grand Prix", "Spanish Grand Prix", "Spanish Grand Prix", "Spanish Grand Prix", "Spanish Grand Prix", "Spanish Grand Prix", "Monaco Grand Prix", "Monaco Grand Prix", "Monaco Grand Prix", "Monaco Grand Prix", "Monaco Grand Prix", "Monaco Grand Prix", "Monaco Grand Prix", "Monaco Grand Prix", "Monaco Grand Prix", "Monaco Grand Prix", "Canadian Grand Prix", "Canadian Grand Prix", "Canadian Grand Prix", "Canadian Grand Prix", "Canadian Grand Prix", "Canadian Grand Prix", "Canadian Grand Prix", "Canadian Grand Prix", "Canadian Grand Prix", "Canadian Grand Prix", "European Grand Prix", "European Grand Prix", "European Grand Prix", "European Grand Prix", "European Grand Prix", "European Grand Prix", "European Grand Prix", "European Grand Prix", "European Grand Prix", "European Grand Prix", "British Grand Prix", "British Grand Prix", "British Grand Prix", "British Grand Prix", "British Grand Prix", "British Grand Prix", "British Grand Prix", "British Grand Prix", "British Grand Prix", "British Grand Prix", "German Grand Prix", "German Grand Prix", "German Grand Prix", "German Grand Prix", "German Grand Prix", "German Grand Prix", "German Grand Prix", "German Grand Prix", "German Grand Prix", "German Grand Prix", "Hungarian Grand Prix", "Hungarian Grand Prix", "Hungarian Grand Prix", "Hungarian Grand Prix", "Hungarian Grand Prix", "Hungarian Grand Prix", "Hungarian Grand Prix", "Hungarian Grand Prix", "Hungarian Grand Prix", "Hungarian Grand Prix", "Belgian Grand Prix", "Belgian Grand Prix", "Belgian Grand Prix", "Belgian Grand Prix", "Belgian Grand Prix", "Belgian Grand Prix", "Belgian Grand Prix", "Belgian Grand Prix", "Belgian Grand Prix", "Belgian Grand Prix", "Italian Grand Prix", "Italian Grand Prix", "Italian Grand Prix", "Italian Grand Prix", "Italian Grand Prix", "Italian Grand Prix", "Italian Grand Prix", "Italian Grand Prix", "Italian Grand Prix", "Italian Grand Prix", "Singapore Grand Prix", "Singapore Grand Prix", "Singapore Grand Prix", "Singapore Grand Prix", "Singapore Grand Prix", "Singapore Grand Prix", "Singapore Grand Prix", "Singapore Grand Prix", "Singapore Grand Prix", "Singapore Grand Prix", "Japanese Grand Prix", "Japanese Grand Prix", "Japanese Grand Prix", "Japanese Grand Prix", "Japanese Grand Prix", "Japanese Grand Prix", "Japanese Grand Prix", "Japanese Grand Prix", "Japanese Grand Prix", "Japanese Grand Prix", "Korean Grand Prix", "Korean Grand Prix", "Korean Grand Prix", "Korean Grand Prix", "Korean Grand Prix", "Korean Grand Prix", "Korean Grand Prix", "Korean Grand Prix", "Korean Grand Prix", "Korean Grand Prix", "Indian Grand Prix", "Indian Grand Prix", "Indian Grand Prix", "Indian Grand Prix", "Indian Grand Prix", "Indian Grand Prix", "Indian Grand Prix", "Indian Grand Prix", "Indian Grand Prix", "Indian Grand Prix", "Abu Dhabi Grand Prix", "Abu Dhabi Grand Prix", "Abu Dhabi Grand Prix", "Abu Dhabi Grand Prix", "Abu Dhabi Grand Prix", "Abu Dhabi Grand Prix", "Abu Dhabi Grand Prix", "Abu Dhabi Grand Prix", "Abu Dhabi Grand Prix", "Abu Dhabi Grand Prix", "United States Grand Prix", "United States Grand Prix", "United States Grand Prix", "United States Grand Prix", "United States Grand Prix", "United States Grand Prix", "United States Grand Prix", "United States Grand Prix", "United States Grand Prix", "United States Grand Prix", "Brazilian Grand Prix", "Brazilian Grand Prix", "Brazilian Grand Prix", "Brazilian Grand Prix", "Brazilian Grand Prix", "Brazilian Grand Prix", "Brazilian Grand Prix", "Brazilian Grand Prix", "Brazilian Grand Prix", "Brazilian Grand Prix" ],
"target": [ "Jenson Button", "Sebastian Vettel", "Lewis Hamilton", "Mark Webber", "Fernando Alonso", "Kamui Kobayashi", "Kimi Rikknen", "Sergio Prez", "Daniel Ricciardo", "Paul di Resta", "McLaren", "Red Bull", "McLaren", "Red Bull", "Ferrari", "Sauber", "Lotus F1", "Sauber", "Toro Rosso", "Force India", "Lewis Hamilton", "Mark Webber", "Fernando Alonso", "Kimi Rikknen", "Sergio Prez", "Paul di Resta", "Bruno Senna", "Jean-ric Vergne", "Nico Hlkenberg", "Michael Schumacher", "Williams", "Toro Rosso", "Force India", "Mercedes", "Jenson Button", "Sebastian Vettel", "Lewis Hamilton", "Mark Webber", "Fernando Alonso", "Kamui Kobayashi", "Bruno Senna", "Nico Rosberg", "Romain Grosjean", "Pastor Maldonado", "Mercedes", "Lotus F1", "Williams", "Sebastian Vettel", "Lewis Hamilton", "Mark Webber", "Fernando Alonso", "Kimi Rikknen", "Paul di Resta", "Michael Schumacher", "Nico Rosberg", "Romain Grosjean", "Felipe Massa", "Ferrari", "Jenson Button", "Sebastian Vettel", "Lewis Hamilton", "Fernando Alonso", "Kamui Kobayashi", "Kimi Rikknen", "Nico Hlkenberg", "Nico Rosberg", "Romain Grosjean", "Pastor Maldonado", "Sebastian Vettel", "Lewis Hamilton", "Mark Webber", "Fernando Alonso", "Kimi Rikknen", "Paul di Resta", "Bruno Senna", "Nico Hlkenberg", "Nico Rosberg", "Felipe Massa", "Sebastian Vettel", "Lewis Hamilton", "Mark Webber", "Fernando Alonso", "Kamui Kobayashi", "Kimi Rikknen", "Sergio Prez", "Nico Rosberg", "Romain Grosjean", "Felipe Massa", "Jenson Button", "Mark Webber", "Fernando Alonso", "Kimi Rikknen", "Sergio Prez", "Paul di Resta", "Bruno Senna", "Nico Hlkenberg", "Michael Schumacher", "Nico Rosberg", "Jenson Button", "Sebastian Vettel", "Lewis Hamilton", "Mark Webber", "Fernando Alonso", "Kimi Rikknen", "Bruno Senna", "Michael Schumacher", "Romain Grosjean", "Felipe Massa", "Jenson Button", "Sebastian Vettel", "Mark Webber", "Fernando Alonso", "Kamui Kobayashi", "Kimi Rikknen", "Sergio Prez", "Nico Hlkenberg", "Michael Schumacher", "Nico Rosberg", "Jenson Button", "Sebastian Vettel", "Lewis Hamilton", "Mark Webber", "Fernando Alonso", "Kimi Rikknen", "Bruno Senna", "Nico Rosberg", "Romain Grosjean", "Felipe Massa", "Jenson Button", "Sebastian Vettel", "Mark Webber", "Kimi Rikknen", "Daniel Ricciardo", "Paul di Resta", "Jean-ric Vergne", "Nico Hlkenberg", "Michael Schumacher", "Felipe Massa", "Lewis Hamilton", "Fernando Alonso", "Kamui Kobayashi", "Kimi Rikknen", "Sergio Prez", "Paul di Resta", "Bruno Senna", "Michael Schumacher", "Nico Rosberg", "Felipe Massa", "Jenson Button", "Sebastian Vettel", "Fernando Alonso", "Kimi Rikknen", "Sergio Prez", "Daniel Ricciardo", "Paul di Resta", "Nico Rosberg", "Romain Grosjean", "Felipe Massa", "Jenson Button", "Sebastian Vettel", "Lewis Hamilton", "Mark Webber", "Kamui Kobayashi", "Kimi Rikknen", "Daniel Ricciardo", "Nico Hlkenberg", "Pastor Maldonado", "Felipe Massa", "Sebastian Vettel", "Lewis Hamilton", "Mark Webber", "Fernando Alonso", "Kimi Rikknen", "Daniel Ricciardo", "Jean-ric Vergne", "Nico Hlkenberg", "Romain Grosjean", "Felipe Massa", "Jenson Button", "Sebastian Vettel", "Lewis Hamilton", "Mark Webber", "Fernando Alonso", "Kimi Rikknen", "Bruno Senna", "Nico Hlkenberg", "Romain Grosjean", "Felipe Massa", "Jenson Button", "Sebastian Vettel", "Fernando Alonso", "Kamui Kobayashi", "Kimi Rikknen", "Daniel Ricciardo", "Paul di Resta", "Bruno Senna", "Pastor Maldonado", "Felipe Massa", "Jenson Button", "Sebastian Vettel", "Lewis Hamilton", "Fernando Alonso", "Kimi Rikknen", "Bruno Senna", "Nico Hlkenberg", "Romain Grosjean", "Pastor Maldonado", "Felipe Massa", "Jenson Button", "Sebastian Vettel", "Mark Webber", "Fernando Alonso", "Kamui Kobayashi", "Kimi Rikknen", "Jean-ric Vergne", "Nico Hlkenberg", "Michael Schumacher", "Felipe Massa" ],
"value": [ 25, 18, 15, 12, 10, 8, 6, 4, 2, 1, 188, 281, 190, 179, 278, 60, 207, 66, 10, 46, 15, 12, 25, 10, 18, 6, 8, 4, 2, 1, 31, 16, 63, 49, 18, 10, 15, 12, 2, 1, 6, 25, 8, 4, 93, 96, 45, 25, 4, 12, 6, 18, 8, 1, 10, 15, 2, 122, 2, 8, 4, 18, 10, 15, 1, 6, 12, 25, 12, 10, 25, 15, 2, 6, 1, 4, 18, 8, 12, 25, 6, 10, 2, 4, 15, 8, 18, 1, 4, 12, 25, 18, 2, 6, 1, 10, 15, 8, 1, 15, 4, 25, 18, 10, 2, 6, 8, 12, 18, 10, 4, 25, 12, 15, 8, 2, 6, 1, 8, 12, 25, 4, 10, 18, 6, 1, 15, 2, 25, 18, 8, 15, 2, 1, 4, 12, 6, 10, 25, 15, 2, 10, 18, 4, 1, 8, 6, 12, 18, 25, 15, 8, 1, 2, 12, 10, 6, 4, 12, 25, 10, 2, 15, 8, 1, 6, 4, 18, 25, 1, 18, 15, 10, 2, 4, 8, 6, 12, 10, 25, 12, 15, 18, 6, 1, 4, 2, 8, 12, 15, 18, 8, 25, 1, 2, 4, 10, 6, 10, 18, 25, 15, 8, 1, 4, 6, 2, 12, 25, 8, 12, 18, 2, 1, 4, 10, 6, 15 ]
},
"nodeWidth": 15,
"nodePadding": 10,
"layout": 32,
"units": "points",
"id": "chart2544fc8157a"
};
params.units ? units = " " + params.units : units = "";
//hard code these now but eventually make available
var formatNumber = d3.format("0,.0f"), // zero decimal places
format = function(d) { return formatNumber(d) + units; },
color = d3.scale.category20();
var svg = d3.select('#' + params.id).append("svg")
.attr("width", params.width)
.attr("height", params.height);
var sankey = d3.sankey()
.nodeWidth(params.nodeWidth)
.nodePadding(params.nodePadding)
.layout(params.layout)
.size([params.width,params.height]);
var path = sankey.link();
var data = params.data,
links = [],
nodes = [];
//get all source and target into nodes
//will reduce to unique in the next step
//also get links in object form
data.source.forEach(function (d, i) {
nodes.push({ "name": data.source[i] });
nodes.push({ "name": data.target[i] });
links.push({ "source": data.source[i], "target": data.target[i], "value": +data.value[i] });
});
//now get nodes based on links data
//thanks Mike Bostock https://groups.google.com/d/msg/d3-js/pl297cFtIQk/Eso4q_eBu1IJ
//this handy little function returns only the distinct / unique nodes
nodes = d3.keys(d3.nest()
.key(function (d) { return d.name; })
.map(nodes));
//it appears d3 with force layout wants a numeric source and target
//so loop through each link replacing the text with its index from node
links.forEach(function (d, i) {
links[i].source = nodes.indexOf(links[i].source);
links[i].target = nodes.indexOf(links[i].target);
});
//now loop through each nodes to make nodes an array of objects rather than an array of strings
nodes.forEach(function (d, i) {
nodes[i] = { "name": d };
});
sankey
.nodes(nodes)
.links(links)
.layout(params.layout);
var link = svg.append("g").selectAll(".link")
.data(links)
.enter().append("path")
.attr("class", "link")
.attr("d", path)
.style("stroke-width", function (d) { return Math.max(1, d.dy); })
.sort(function (a, b) { return b.dy - a.dy; });
link.append("title")
.text(function (d) { return d.source.name + " → " + d.target.name + "\n" + format(d.value); });
var node = svg.append("g").selectAll(".node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function (d) { return "translate(" + d.x + "," + d.y + ")"; })
.call(d3.behavior.drag()
.origin(function (d) { return d; })
.on("dragstart", function () { this.parentNode.appendChild(this); })
.on("drag", dragmove));
node.append("rect")
.attr("height", function (d) { return d.dy; })
.attr("width", sankey.nodeWidth())
.style("fill", function (d) { return d.color = color(d.name.replace(/ .*/, "")); })
.style("stroke", function (d) { return d3.rgb(d.color).darker(2); })
.append("title")
.text(function (d) { return d.name + "\n" + format(d.value); });
node.append("text")
.attr("x", -6)
.attr("y", function (d) { return d.dy / 2; })
.attr("dy", ".35em")
.attr("text-anchor", "end")
.attr("transform", null)
.text(function (d) { return d.name; })
.filter(function (d) { return d.x < params.width / 2; })
.attr("x", 6 + sankey.nodeWidth())
.attr("text-anchor", "start");
// the function for moving the nodes
function dragmove(d) {
d3.select(this).attr("transform",
"translate(" + (
d.x = Math.max(0, Math.min(params.width - d.dx, d3.event.x))
) + "," + (
d.y = Math.max(0, Math.min(params.height - d.dy, d3.event.y))
) + ")");
sankey.relayout();
link.attr("d", path);
}
</script>
</body>
<!-- Google Prettify -->
<script src="http://cdnjs.cloudflare.com/ajax/libs/prettify/188.0.0/prettify.js"></script>
<script
src='https://google-code-prettify.googlecode.com/svn-history/r232/trunk/src/lang-r.js'>
</script>
<script>
var pres = document.getElementsByTagName("pre");
for (var i=0; i < pres.length; ++i) {
pres[i].className = "prettyprint linenums";
}
prettyPrint();
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment