corybrunson / ggalluvial

ggplot2 extension for alluvial plots
http://corybrunson.github.io/ggalluvial/
GNU General Public License v3.0
497 stars 34 forks source link

experiment / implement different curves #42

Closed corybrunson closed 4 years ago

corybrunson commented 5 years ago

Different Sankey diagram, parallel sets plot, and alluvial plot generators render flows between axes using different curves. This blog post by Jeffrey A. Shaffer discusses and showcases several options. More than the current single option should be made available, if possible through the grid package, and the default should be informed by Shaffer's discussion and perhaps also by this paper by Matthias Schonlau introducing the hammock plots implemented in ggparallel.

corybrunson commented 5 years ago

x-splines should remain the default, since they are, uniquely, already implemented in the grid package. Though the knot positioning may be improved.

Alternative shapes can be generated using grid::polygonGrob() after segmenting each flow data set into one that outlines the segmented flow curve, with resolution specified by a segments parameter. The segmentation can invoke one of several implemented functions that map the unit interval to itself. Here are some candidates, adapted from Shaffer's blog post:

unit_cubic <- function(x) 3*x^2 - 2*x^3
unit_quintic <- function(x) 10*x^3 - 15*x^4 + 6*x^5
unit_sine <- function(x) {
  t <- (x - .5) * pi
  sin(t) / 2 + .5
}
unit_arctangent <- function(x, scale.arctangent = sqrt(3)) {
  t <- (x - .5) * scale.arctangent * 2
  atan(t) / 2 + .5
}
unit_sigmoid <- function(x, scale.sigmoid = 3) {
  t <- (x - .5) * scale.sigmoid * 2
  plogis(t)
}

Additionally, the layer could accept a custom function and conduct a minimal check that it takes 0 to 0 and 1 to 1.

corybrunson commented 4 years ago

This is underway in the ribbons branch. Functionality may be complete but tests and examples are needed.

corybrunson commented 4 years ago

Commit 6d5b75550478b1c08f58f9dc05afe9aba903e3c0 provides a near-optimal approach using splines with shape parameter -.5. It's convenient to use splines to approximate the alternative curves since xsplineGrob() is already in use in GeomAlluvium() and GeomFlow(), though the internal calculations slow the rendering. It would also be possible to simply set shape = 0 (piecewise linear approximations despite the overkill grob) and require more segments to obtain better approximations, though it's not clear whether this would alleviate the limits on segments or noticeably speed up the rendering. Ultimately it may be better to simply use segment grobs for the alternative curves, since otherwise the segments parameter is misleading and the behavior a bit cryptic.

corybrunson commented 4 years ago

Commit 4dc6127f3aa626a1870e653bd77d76da4d98e41b reverts to piecewise-linear approximations. On closer inspection, splines introduced higher-degree errors without rendering in substantially less time than simple segmentation.

corybrunson commented 4 years ago

These have been implemented in v0.12.0, which was released from 5ea1f2df20711416621521da4d5f815a998e717d.