Estoy tramando un CDF discreto. Tengo algunas preguntas sobre geom_step que no encuentro al usar Google.

  1. ¿Es posible hacer que el segmento de línea que representa el salto sea discontinuo en lugar de sólido para mostrar mejor lo que está sucediendo?
  2. ¿Es posible agregar geom_point más eficientemente que yo? (menos c / p).

A continuación se muestra mi solución actual:

library(tidyverse)
library(ggthemes)
theme_set(theme_few())

x0 <- seq(-0.5, -0.01, by = 0.01)
x1 <- seq(0, 0.99, by = 0.02)
x2 <- seq(1, 1.99, by = 0.02)
x3 <- seq(2, 2.99, by = 0.02)
x35 <- seq(3, 3.49, by = 0.01)
x4 <- seq(3.5, 3.99, by = 0.01)

tibble_ex <- tibble(
  x0 = x0,
  x1 = x1,
  x2 = x2,
  x3 = x3,
  x35 = x35,
  x4 = x4
)

tibble_ex %>%
  gather(x, xax, x0:x4) %>%
  mutate(cdf = case_when(x == 'x0' ~ 0,
                         x == 'x1' ~ 1/2,
                         x == 'x2' ~ 3/5,
                         x == 'x3' ~ 4/5,
                         x == 'x35' ~ 9/10,
                         x == 'x4' ~ 1)) %>%
  ggplot(aes(x = xax, y = cdf)) +
  geom_step() +
  geom_point(aes(x = 0, y = 0), size = 3, shape = 21, fill = 'white') +
  geom_point(aes(x = 1, y = 0.5), size = 3, shape = 21, fill = 'white') +
  geom_point(aes(x = 2, y = 3/5), size = 3, shape = 21, fill = 'white') +
  geom_point(aes(x = 3, y = 4/5), size = 3, shape = 21, fill = 'white') +
  geom_point(aes(x = 3.5, y = 9/10), size = 3, shape = 21, fill = 'white') +
  geom_point(aes(x = 0, y = 0.5), size = 3, shape = 21, fill = 'black') +
  geom_point(aes(x = 1, y = 3/5), size = 3, shape = 21, fill = 'black') +
  geom_point(aes(x = 2, y = 4/5), size = 3, shape = 21, fill = 'black') +
  geom_point(aes(x = 3, y = 9/10), size = 3, shape = 21, fill = 'black') +
  geom_point(aes(x = 3.5, y = 1), size = 3, shape = 21, fill = 'black') +
  labs(x = 'x', y = 'F(x)')

enter image description here

1
docjay 8 sep. 2018 a las 18:08

3 respuestas

La mejor respuesta

Ggplot será más potente de usar si puede poner sus datos en un marco de datos y estructurarlos para que las características de sus datos puedan mapearse directamente.

Aquí hay una manera de tomar sus datos y aumentarlos con filas adicionales que representan los puntos de conexión, haciendo coincidir cada x con el valor cdf anterior. Agregué una columna, type, para hacer un seguimiento de cuál es cuál. También organizo df para que geom_segment trace los puntos en el orden correcto.

new_steps <- 
  tibble(x = c(0:3, 3.5, 4),
         cdf = c(0, .5, .6, .8, .9, 1))


df <- new_steps %>%
  mutate(type = "cdf") %>%
  bind_rows(new_steps %>%
              mutate(type = "prior",
                     cdf = lag(cdf))) %>%
  drop_na() %>%
  arrange(x, desc(type))

Luego podemos mapear los puntos 'fill y el tipo de línea geom_segments' a type.

ggplot(df) + 
  geom_point(aes(x, cdf, fill = type),
             shape = 21) +
  scale_fill_manual(values = c("black", "white")) +
  geom_segment(aes(x = lag(x), y = lag(cdf),
                   xend = x, yend = cdf,
                   lty = type)) +
  scale_linetype_manual(values = c("dashed", "solid"))

plot with dashed vertical lines

2
A. Suliman 8 sep. 2018 a las 17:36

Para la segunda parte de su pregunta, puede poner todas las coordenadas en un marco de datos separado y llamar a geom_point solo una vez:

ddf <- data.frame(xax = rep(c(0:3, 3.5), 2),
                  cdf = c(0, .5, .6, .8, .9, .5, .6, .8, .9, 1),
                  col = rep(c("white", "black"), each = 5))
dev.new()
tibble_ex %>%
  gather(x, xax, x0:x4) %>%
  mutate(cdf = case_when(x == 'x0' ~ 0,
                         x == 'x1' ~ 1/2,
                         x == 'x2' ~ 3/5,
                         x == 'x3' ~ 4/5,
                         x == 'x35' ~ 9/10,
                         x == 'x4' ~ 1)) %>%
  ggplot(aes(x = xax, y = cdf)) +
  geom_step() +
  geom_point(data = ddf, aes(fill = I(col)), size = 3, shape = 21) +
  labs(x = 'x', y = 'F(x)')
0
thothal 8 sep. 2018 a las 15:31

(1) No, no hay una forma integrada de hacer que geom_step esté a medias. Pero si publica esto como una pregunta separada, tal vez alguien lo ayudará a crear una nueva geom para esto.

(2) La respuesta es poner los puntos que desea trazar en un marco de datos, como cualquier otra cosa que desee trazar:

point_data = data.frame(x = rep(c(0, 1, 2, 3, 3.5), 2),
                        y = c(0, rep(c(.5, .6, .8, .9), 2), 1),
                        z = rep(c("a", "b"), each = 5))

# calling your gathered/mutated version of tibble_ex df
ggplot(df, aes(x = xax, y = cdf)) +
  geom_step() +
  geom_point(data = point_data, aes(x = x, y = y, fill = z), shape = 21) +
  scale_fill_manual(values = c("white", "black"), guide = FALSE) +
  labs(x = 'x', y = 'F(x)')
0
Gregor Thomas 8 sep. 2018 a las 15:30