I'm trying to make a bumps chart (like parallel coordinates but with an ordinal x-axis) to show ranking over time. I can make a straight-line chart very easily:
library(ggplot2)
set.seed(47)
df <- as.data.frame(as.table(replicate(8, sample(4))), responseName = 'rank')
df$Var2 <- as.integer(df$Var2)
head(df)
#> Var1 Var2 rank
#> 1 A 1 4
#> 2 B 1 2
#> 3 C 1 3
#> 4 D 1 1
#> 5 A 2 3
#> 6 B 2 4
ggplot(df, aes(Var2, rank, color = Var1)) + geom_line() + geom_point()
Wonderful. Now, though, I want to make the connecting lines curved. Despite never having more than one y per x, geom_smooth
offers some possibilities. loess
seems like it should work, as it can ignore points except the closest. However, even with tweaking the best I can get still misses lots of points and overshoots others where it should be flat:
ggplot(df, aes(Var2, rank, color = Var1)) +
geom_smooth(method = 'loess', span = .7, se = FALSE) +
geom_point()
I've tried a number of other splines, like ggalt::geom_xspline
, but they all still overshoot or miss the points:
ggplot(df, aes(Var2, rank, color = Var1)) + ggalt::geom_xspline() + geom_point()
Is there an easy way to curve these lines? Do I need to build my own sigmoidal spline? To clarify, I'm looking for something like D3.js's d3.curveMonotoneX
which hits every point and whose local maxima and minima do not exceed the y values:
Ideally it would probably have a slope of 0 at each point, too, but that's not absolutely necessary.
cobs
package? "COBS stands for Constrained B-splines. Possible constraints include going through specific points, setting derivatives to specified values, monotonicity (increasing or decreasing), concavity, convexity, periodicity, etc." I can't immediately get it to work but there's promise. – Dividersfda::smooth.monotone
, but it's parameters are ridiculously complex. – Pushedgeom_smooth(method = 'loess', span = 0.3, se = FALSE, method.args=list(degree=1))
– Germ