R - ggplot2 'dodge' geom_step () to overlay geom_bar ()

Calculations using ggplot2 geom_bar(stat="identity")

are an efficient method for visualizing samples. I would like to use this method to display my observable counts and compare them to the expected counts, which I would like to use geom_step

to overlay a storyline layer on top of the panel.

However, when I do this, I am faced with the problem that by default the bubbles have their positions, but geom_step

not. For example, using both continuous and discrete dependent variables:

library(tidyverse)

test <- data_frame(a = 1:10, b = runif(10, 1, 10))

test_plot <- ggplot(test, aes(a, b)) + 
  geom_bar(stat="identity") + 
  geom_step(color = 'red')

test2 <- data_frame(a = letters[1:10], b = runif(10, 1, 10))

test2_plot <- ggplot(test2, aes(a, b, group = 1)) + 
  geom_bar(stat="identity") + 
  geom_step(color = 'red'))

gridExtra::grid.arrange(test_plot, test2_plot, ncol = 2)

      

enter image description here

As you can see, the two layers are offset, which is undesirable.

Reading the docs I can see it geom_path

has a parameter position =

, however trying something like geom_step(color = 'red', position = position_dodge(width = 0.5))

it doesn't do what I want, rather it shrinks the bars and stairstep line towards the center. Another option is to set up the data directly like this geom_step(aes(a-0.5, b), color = 'red')

, which gives an almost acceptable result for data with continuous dependent variables. You can also calculate the line of the aging line as a function and plot it with stat_function()

.

enter image description here

However, these approaches do not apply to data with discrete dependent variables, and my actual data has discrete dependent variables, so I need another answer.

Also, as you move, the start bar will not span the last bar as shown in the above image. Is there a simple elegant way to extend it to cover the last bar?

If geom_step()

- the wrong approach, and what I am trying to get can be achieved in another way, I am interested in that too.

+3


source to share


2 answers


I think the most efficient way to solve this problem is to define custom geometry like this:

library(tidyverse)

geom_step_extend <- function(data, extend = 1, nudge = -0.5,
                             ...) {
  # Function for computing the last segment data
  get_step_extend_data <- function(data, extend = 1, nudge = -0.5) {
    data_out <- as.data.frame(data[order(data[[1]]), ])
    n <- nrow(data)
    max_x_y <- data_out[n, 2]
    if (is.numeric(data_out[[1]])) {
      max_x <- data_out[n, 1] + nudge
    } else {
      max_x <- n + nudge
    }

    data.frame(x = max_x,
               y = max_x_y,
               xend = max_x + extend,
               yend = max_x_y)
  }

  # The resulting geom
  list(
    geom_step(position = position_nudge(x = nudge), ...),
    geom_segment(
      data = get_step_extend_data(data, extend = extend, nudge = nudge),
      mapping = aes(x = x, y = y,
                    xend = xend, yend = yend),
      ...
    )
  )
}

set.seed(111)
test <- data_frame(a = 1:10, b = runif(10, 1, 10))
test2 <- data_frame(a = letters[1:10], b = runif(10, 1, 10))

test_plot <- ggplot(test, aes(a, b, group = 1)) + 
  geom_bar(stat = "identity") + 
  geom_step_extend(data = test, colour = "red")

test2_plot <- ggplot(test2, aes(a, b, group = 1)) + 
  geom_bar(stat = "identity") + 
  geom_step_extend(data = test2, colour = "red")

gridExtra::grid.arrange(test_plot, test2_plot, ncol = 2)

      

Example_output



Basically, this solution has three parts:

  • Move to the left with a position_nudge

    stepped curve at the desired value (in this case -0.5);
  • Calculate the missing (what's on the right) segment data using the function get_step_extend_data

    . His behavior is inspired ggplot2:::stairstep

    , which is the main function geom_step

    ;
  • Compose geom_step

    with geom_segment

    in separate geometry with list

    .
+2


source


Here's a rather crude solution, but should work in this case.

Create an alternate dataframe that expanded each row to extend the x-axis by -0.5 and 0.5:

test2 <- data.frame(a = lapply(1:nrow(test), function(x) c(test[x,"a"]-.5, test[x,"a"], test[x, "a"]+0.5)) %>% unlist, 
                b = lapply(1:nrow(test), function(x) rep(test[x,"b"], 3)) %>% unlist)

      

Draw a path with the geom_line argument:

ggplot(test, aes(a,b)) + geom_bar(stat="identity", alpha=.7) + geom_line(data=test2, colour="red")

      



enter image description here

It will look neater if you set the geom_bar width to 1:

ggplot(test, aes(a,b)) + geom_bar(width=1, stat="identity", alpha=.7) + geom_line(data=test2, colour="red")

      

enter image description here

+1


source







All Articles