Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make rounded lineends in ggplot - both in plot and in legend

Tags:

r

ggplot2

I am trying to match some graphs to each other. Some were made in Sigmaplot and I don't have access to the data. So that means that my new graphs have to look as similar as possible, and I'm using ggplot to achieve that. I have added a million tiny details to make them more similar, but one detail still eludes me.

The line ends are supposed to be rounded, which I have managed to do for the plot itself by setting lineend = "round" in geom_line(). However, the line ends in the legend still have a butt end. I am a stickler for consistency and every detail being just so, which means I really can't accept that...

Here is an example.

var1 <- seq(1,100,10)
var2 <- c(1:10)
trt <- c("t1", "t1", "t1", "t1", "t1", "t2", "t2", "t2", "t2", "t2")
my.df <- data.frame(var1, var2, trt)


ggplot(data = my.df, aes(x = var1, y = var2, col = trt))+
  geom_line(size = 3, lineend = "round")
like image 416
Meerkat Avatar asked Jan 26 '23 16:01

Meerkat


1 Answers

In the ggplot2 package, the legend key for geom_line is hard coded to lineend = "butt":

> GeomLine$draw_key
<ggproto method>
  <Wrapper function>
    function (...) 
f(...)

  <Inner function (f)>
    function (data, params, size) 
{
    data$linetype[is.na(data$linetype)] <- 0
    segmentsGrob(0.1, 0.5, 0.9, 0.5, gp = gpar(col = alpha(data$colour, 
        data$alpha), lwd = data$size * .pt, lty = data$linetype, 
        lineend = "butt"), arrow = params$arrow)
}

We can define our own, slightly different version geom_line2() with legend key lineend = "round" instead:

library(grid)

GeomLine2 <- ggproto(
  "GeomLine2", GeomLine,
  draw_key =  function (data, params, size) {
    data$linetype[is.na(data$linetype)] <- 0
    segmentsGrob(0.3, 0.5, 0.7, 0.5, # I modified the x0 / x1 values here too, to shift
                                     # the start / end points closer to the centre in order
                                     # to leave more space for the rounded ends
                 gp = gpar(col = alpha(data$colour, data$alpha), 
                           lwd = data$size * .pt, 
                           lty = data$linetype, 
                           lineend = "round"),
                 arrow = params$arrow)
  })

geom_line2 <- function (mapping = NULL, data = NULL, stat = "identity", position = "identity", 
                        na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, ...) {
  layer(data = data, mapping = mapping, stat = stat, 
        geom = GeomLine2, # this is the only change from geom_line to geom_line2
        position = position, show.legend = show.legend, inherit.aes = inherit.aes, 
        params = list(na.rm = na.rm, ...))}

Result:

cowplot::plot_grid(

  ggplot(data = my.df, aes(x = var1, y = var2, col = trt))+
    geom_line(size = 3, lineend = "round") +
    ggtitle("original geom_line"),

  ggplot(data = my.df, aes(x = var1, y = var2, col = trt))+
    geom_line2(size = 3, lineend = "round") +
    ggtitle("modified geom_line2"),

  ncol = 1
)

plot

like image 103
Z.Lin Avatar answered Feb 19 '23 10:02

Z.Lin