使用dplyr + ggplot2

时间:2018-06-09 10:15:17

标签: r ggplot2 dplyr

我试图说明输入位如何影响四步旋转散列中的输出位。哈希函数如下所示:

#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
uint32_t rotating_hash(uint32_t state, uint32_t input)
{
    uint32_t hash = state;
    uint8_t *p = (uint8_t*)&input;
    //      mix          ; combine
    hash ^=                *(p++);
    hash += rot(hash, 4) ^ *(p++);
    hash += rot(hash, 4) ^ *(p++);
    hash += rot(hash, 4) ^ *p;
    return hash;
}

其中,为简单起见,我假设加法中的位只影响它们已经存在的相同位置。实际函数不是那么重要,但它是一个过程,其中一步的每一位都会影响它下面的两位

我计算一个级别的位会影响它们之下的位,如下所示:

library(tibble)
library(dplyr)
library(magrittr)

rot_hash_positions <- function(bit) {
  operation_1 <- bit
  operation_2 <- outer(operation_1, c(4, 0, -28), FUN = '+')  %>% as.vector() %>% { . %% 32 }
  operation_3 <- outer(operation_2, c(4, 0, -28), FUN = '+')  %>% as.vector() %>% { . %% 32 }
  operation_4 <- outer(operation_3, c(4, 0, -28), FUN = '+')  %>% as.vector() %>% { . %% 32 }
  rbind(tibble(bit = bit, operation = 1, positions = operation_1),
        tibble(bit = bit, operation = 2, positions = operation_2),
        tibble(bit = bit, operation = 3, positions = operation_3),
        tibble(bit = bit, operation = 4, positions = operation_4))
}

bit_movement <- do.call(rbind, lapply(0:31, rot_hash_positions))

,结果如下:

> bit_movement %>% filter(bit == 0)
# A tibble: 10 x 3
     bit operation positions
   <int>     <dbl>     <dbl>
 1     0         1         0
 2     0         2         4
 3     0         2         0
 4     0         3         8
 5     0         3         4
 6     0         3         0
 7     0         4        12
 8     0         4         8
 9     0         4         4
10     0         4         0

该函数计算旋转操作的两个值,但模数32成为一个位置,我使用unique()摆脱了重复。

现在我想绘制这个。到目前为止,我的尝试看起来像这样:

library(ggplot2)

plot_bitmovement <- function(bit_movement, highlight_bits) {
  ggplot(bit_movement, aes(
    y = positions,
    x = operation,
    group = factor(bit, levels = 1:32)
  )) +
    geom_line(colour = "gray") +
    geom_point(colour = "gray") +
    geom_line(data = highlight_bits, colour = "black") +
    geom_point(data = highlight_bits, colour = "black") +
    coord_flip() +
    scale_y_reverse(breaks = 0:31, labels = 1:32) +
    scale_x_reverse() +
    theme_minimal() +
    theme(
      legend.position = "none"
    ) + ylab("Bit-position") + xlab("Operation")
}

我突出显示图中的第一个或最后一个字节:

bit_movement <- do.call(rbind, lapply(0:31, rot_hash_positions))
plot_bitmovement(bit_movement, bit_movement %>% filter(bit < 8))

Highlighted first byte that is added.

last_byte <- tibble(bit = 0:7, operation = 4, positions = 0:7)
plot_bitmovement(bit_movement, last_byte)

Highlighted last byte that is added.

在这种情况下,最后一个字节不太有趣,但是我需要可视化其他一些哈希函数以及它变得更有趣。

现在我的问题是这样的:当我使用geom_line()绘制位移动时,我不会从一个y轴水平到下一个水平线获得线段,但是除了第一步之外的所有水平线段都是一级到下一级。我想要的只是从一个级别到下一个级别的段。我不完全确定如何做到这一点。

我认为geom_linesegment是要走的路,在这种情况下,我需要将我的bit_movement数据框修改为具有我想要的线段的起点和终点位置的东西,但我不确定如何以优雅的方式做到这一点。由于我需要绘制几个相似的数字,我宁愿不必过多地对数据操作进行硬连接。

有什么建议吗?

1 个答案:

答案 0 :(得分:0)

我想出了这个主意。我不确定它有多优雅,所以我仍然喜欢它的评论。

library(purrr)
get_steps <- function(bm, step) {
  op1 <- bm %>%
    filter(operation == !!(step-1)) %>%
    mutate(x = operation, y = positions) %>%
    select(bit, x, y)
  op2 <- bm %>%
    filter(operation == !!step) %>%
    mutate(xend = operation, yend = positions) %>%
    select(bit, xend, yend)
  inner_join(op1, op2, by = "bit")
}

plot_bitmovement <- function(bit_movement, highlight_bits) {
  bm_segs <- map(2:4, ~ get_steps(bit_movement, .x)) %>% bind_rows()
  hl_segs <- map(2:4, ~ get_steps(highlight_bits, .x)) %>% bind_rows()
  ggplot(bm_segs, aes(
    x = x, 
    y = y, 
    xend = xend,
    yend = yend)
  ) + 
    geom_segment(colour = "grey") +
    geom_point(colour = "grey") + 
    geom_point(aes(x = xend, y = yend), colour = "grey") +
    geom_segment(data = hl_segs, colour = "black") + 
    geom_point(data = hl_segs, colour = "black") +
    geom_point(aes(x = xend, y = yend), data = hl_segs, colour = "black") +
    coord_flip() +
    scale_y_reverse(breaks = 0:31, labels = 1:32) +
    scale_x_reverse() +
    theme_minimal() +
    theme(
      legend.position = "none"
    ) + ylab("Bit-position") + xlab("Operation")
}

bit_movement <- do.call(rbind, lapply(0:31, rot_hash_positions))
plot_bitmovement(bit_movement, bit_movement %>% filter(bit < 8))

Flow of first byte with geom_segment.

更新:不,这也不太正确。现在我看到的动作比我应该多,因为我将所有位置合并到一个级别以下。不过,这是rot_hash_positions中的一个错误,所以我会自己给它一个。