Ggplot2 geom_rug () produces a different line length with a wide plot

I posted this as a follow-up to the "sibling" question with a grid (ie Lattice's` panel.rug "produces a different line length with a wide plot ), but because of the different graphics system that it deserves to be separate.

When creating a wide graph in ggplot2 with fields that include geom_rug() from ggthemes , the length of the lines in strong margins is longer along the y axis than along the x axis:

 library(ggplot2) library(ggthemes) png(width=800, height=400) ggplot(swiss, aes(Education, Fertility)) + geom_point() + geom_rug() dev.off() 

enter image description here

I would like these rug lines in the x- and y-axes to be the same length, regardless of the shape of the plot (note: right now the carpet lines will be the same length when the graph is square).

+8
source share
5 answers

This followed the current previous geom_rug code, but modified it to add (or subtract) the absolute sum for the internal tick units of geom_rug . This is really a grid::unit -function application more than anything else, as it takes advantage of the fact that units can be added and subtracted for various reasons. You can change it so that it accepts rug_len -argument with the default value, say, a unit of measure (0.5, "cm"). (Remember to set the environment functions so that one closure, geom_rug2 , can cause geom_rug2 call the next closure, ggplot2::'+' .)

 geom_rug2 <- function (mapping = NULL, data = NULL, stat = "identity", position = "identity", sides = "bl", ...) { GeomRug2$new(mapping = mapping, data = data, stat = stat, position = position, sides = sides, ...) } GeomRug2 <- proto(ggplot2:::Geom, { objname <- "rug2" draw <- function(., data, scales, coordinates, sides, ...) { rugs <- list() data <- coord_transform(coordinates, data, scales) if (!is.null(data$x)) { if(grepl("b", sides)) { rugs$x_b <- segmentsGrob( x0 = unit(data$x, "native"), x1 = unit(data$x, "native"), y0 = unit(0, "npc"), y1 = unit(0, "npc")+unit(1, "cm"), gp = gpar(col = alpha(data$colour, data$alpha), lty = data$linetype, lwd = data$size * .pt) ) } if(grepl("t", sides)) { rugs$x_t <- segmentsGrob( x0 = unit(data$x, "native"), x1 = unit(data$x, "native"), y0 = unit(1, "npc"), y1 = unit(1, "npc")-unit(1, "cm"), gp = gpar(col = alpha(data$colour, data$alpha), lty = data$linetype, lwd = data$size * .pt) ) } } if (!is.null(data$y)) { if(grepl("l", sides)) { rugs$y_l <- segmentsGrob( y0 = unit(data$y, "native"), y1 = unit(data$y, "native"), x0 = unit(0, "npc"), x1 = unit(0, "npc")+unit(1, "cm"), gp = gpar(col = alpha(data$colour, data$alpha), lty = data$linetype, lwd = data$size * .pt) ) } if(grepl("r", sides)) { rugs$y_r <- segmentsGrob( y0 = unit(data$y, "native"), y1 = unit(data$y, "native"), x0 = unit(1, "npc"), x1 = unit(1, "npc")-unit(1, "cm"), gp = gpar(col = alpha(data$colour, data$alpha), lty = data$linetype, lwd = data$size * .pt) ) } } gTree(children = do.call("gList", rugs)) } default_stat <- function(.) StatIdentity default_aes <- function(.) aes(colour="black", size=0.5, linetype=1, alpha = NA) guide_geom <- function(.) "path" }) environment(geom_rug2) <- environment(ggplot) p <- qplot(x,y) p + geom_rug2(size=.1) 

With your code creating png, I get:

enter image description here

I also tried following Hadley's current description of how to extend ggplot2 without much success.

+8
source

I'm not sure if there is a way to control the bucket segment length in geom_rug (I could not find it). However, you can create your own rug with geom_segment and hard- geom_segment length of the segment or add some logic to programmatically create lines to align the length. For instance:

 # Aspect ratio ar = 0.33 # Distance from lowest value to start of rug segment dist = 2 # Rug length factor rlf = 2.5 ggplot(swiss, aes(Education, Fertility)) + geom_point() + geom_segment(aes(y=Fertility, yend=Fertility, x=min(swiss$Education) - rlf*ar*dist, xend=min(swiss$Education) - ar*dist)) + geom_segment(aes(y=min(swiss$Fertility) - rlf*dist, yend=min(swiss$Fertility) - dist, x=Education, xend=Education)) + coord_fixed(ratio=ar, xlim=c(min(swiss$Education) - rlf*ar*dist, 1.03*max(swiss$Education)), ylim=c(min(swiss$Fertility) - rlf*dist, 1.03*max(swiss$Fertility))) 

enter image description here

Or, if you just want to write it hard:

 ggplot(swiss, aes(Education, Fertility)) + geom_point() + geom_segment(aes(y=Fertility, yend=Fertility, x=min(swiss$Education) - 3, xend=min(swiss$Education) - 1.5)) + geom_segment(aes(y=min(swiss$Fertility) - 6, yend=min(swiss$Fertility) - 3, x=Education, xend=Education)) + coord_cartesian(xlim=c(min(swiss$Education) - 3, 1.03*max(swiss$Education)), ylim=c(min(swiss$Fertility) - 6, 1.03*max(swiss$Fertility))) 
+6
source

Entry into the ggplot grob structure:

Minor change: upgrade to ggplot2 2.2.1

 library(ggplot2) p = ggplot(swiss, aes(Education, Fertility)) + geom_point() + geom_rug() # Get the ggplot grob gp = ggplotGrob(p) # Set end points of rug segments library(grid) gp$grobs[[6]]$children[[4]]$children[[1]]$y1 = unit(0.03, "snpc") gp$grobs[[6]]$children[[4]]$children[[2]]$x1 = unit(0.03, "snpc") png(width=900, height=300) grid.draw(gp) dev.off() 

enter image description here

+2
source

Starting with ggplot2 v3.2.0, you can pass the length argument to geom_rug () to indicate the absolute length of the rug:

 library(ggplot2) library(ggthemes) png(width=800, height=400) ggplot(swiss, aes(Education, Fertility)) + geom_point() + geom_rug(length = unit(0.5,"cm")) dev.off() 

Fixed Length Geom_rug

+2
source

Another solution under the hood. First, I get ggplot grob, and then I use the editGrob function from the grid package. With editGrob I just call the coffin for editing; this is easier than monitoring the structure of the soil down to the appropriate parameters. Normally editGrob cannot see all the verbs ggplot, but they can be set using grid.force() .

 library(ggplot2) library(grid) p = ggplot(swiss, aes(Education, Fertility)) + geom_point() + geom_rug() # Get the ggplot grob gp = ggplotGrob(p) # Get names of relevant grobs. # The grid.force function generates the gtable at-drawing-time contents. names.grobs = grid.ls(grid.force(gp))$name # We're interested in the children of rugs.gTree segments = names.grobs[which(grepl("GRID.segments", names.grobs))] # Check them out str(getGrob(grid.force(gp), gPath(segments[1]))) # Note: y1 = 0.03 npc str(getGrob(grid.force(gp), gPath(segments[2]))) # Note: x1 = 0.03 npc # Set y1 and x1 to 0.03 snpc gp = editGrob(grid.force(gp), gPath(segments[1]), y1 = unit(0.03, "snpc")) gp = editGrob(grid.force(gp), gPath(segments[2]), x1 = unit(0.03, "snpc")) png(width=900, height=300) grid.draw(gp) dev.off() 
+1
source

All Articles