首页 > 解决方案 > 展开现有数据框中的条目

问题描述

我在一个函数中有一些代码,我希望用它来围绕 ggplot 中的点创建类似热图的效果。[col, row] 坐标来自在 Excel 中完成的 2D 地图模型......诚然很笨拙,但这就是我现在必须使用的。

在任何情况下,下面的 reprex 在传递点值时都会产生预期的效果,但是non-numeric argument to binary operator当我尝试应用于存储在数据框中的点向量时出现错误。感谢您的任何见解!

  library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
  library(tidyr)
  library(purrr)
  library(tibble)
  library(stringr)
  
  get_circle_kernel <- function(col_pts = 10,
                                row_pts = 10,
                                radius = 5L,
                                jitter = 5L) {
    # sample the row and column jitter to move the circle center
    col_jitter <- sample(-jitter:jitter, size = 1)
    row_jitter <- sample(-jitter:jitter, size = 1)
    
    # update col_pts and row_pts to move circle center
    col_pts <- col_pts + col_jitter
    row_pts <- row_pts + row_jitter
    
    # draw a filled circle of points with alpha for each [row_pts, col_]
    # from https://stackoverflow.com/questions/14285358/find-all-integer-coordinates-in-a-given-radius
    df_circle <- tibble::tibble(
      row = (row_pts - radius):(row_pts + radius),
      col = (col_pts - radius):(col_pts + radius)
    ) %>% tidyr::expand(row, col) %>%
      dplyr::mutate(radius_from_center = sqrt((row - row_pts) ^ 2 + (col - col_pts) ^
                                                2)) %>%
      dplyr::filter(radius_from_center <= radius) %>%
      dplyr::mutate(alpha = (max(radius_from_center) ^ 2 - radius_from_center ^
                               2) / max(radius_from_center) ^ 2)
    
    return(df_circle)
  }
  
  # Plots for testing & noodling --------------------------------------------
  
  df_1 <- get_circle_kernel()

  ggplot2::ggplot(df_1, ggplot2::aes(x = col, y = row, alpha = alpha)) +
    ggplot2::geom_raster(interpolate = FALSE, fill = "red") +
    ggplot2::scale_x_continuous(limits = c(0, 20)) +
    ggplot2::scale_y_continuous(limits = c(0, 20))



# Example applying to df --------------------------------------------------

  df_2 <- tibble::tibble(col = c(10, 30, 50),
                          row = c(10, 30, 50),
                          radius_from_center = rep(0, 3),
                          alpha = rep(1, 3)) %>% 
    purrr::map_df(~get_circle_kernel(col_pts = col, row_pts = row))
#> Error in col_pts + col_jitter: non-numeric argument to binary operator

reprex 包于 2021-02-19 创建(v1.0.0)

标签: rtidyverse

解决方案


要么使用rowwise

library(dplyr)
library(purrr)
df_2 %>%
   rowwise %>%
    mutate(out = list(get_circle_kernel(col_pts = col, row_pts = row))) %>%
   ungroup

-输出

# A tibble: 3 x 5
#    col   row radius_from_center alpha out              
#  <dbl> <dbl>              <dbl> <dbl> <list>           
#1    10    10                  0     1 <tibble [81 × 4]>
#2    30    30                  0     1 <tibble [81 × 4]>
#3    50    50                  0     1 <tibble [81 × 4]>

如果我们想要一个数据集(基于函数,列也在“out”内重复)

df_2 %>%
    rowwise %>%
     transmute(out = list(get_circle_kernel(col_pts = col, row_pts = row))) %>%
    ungroup %>% unnest(c(out))
# A tibble: 243 x 4
#     row   col radius_from_center alpha
#   <int> <int>              <dbl> <dbl>
# 1     5     9               5    0    
# 2     6     6               5    0    
# 3     6     7               4.47 0.200
# 4     6     8               4.12 0.32 
# 5     6     9               4    0.36 
# 6     6    10               4.12 0.32 
# 7     6    11               4.47 0.200
# 8     6    12               5    0    
# 9     7     5               5    0    
#10     7     6               4.24 0.28 
# … with 233 more rows

或指定map2mutate

 df_2 %>%
        mutate(out = map2(col, row, ~get_circle_kernel(col_pts = .x, row_pts = .y)))

-输出

# A tibble: 3 x 5
#    col   row radius_from_center alpha out              
#  <dbl> <dbl>              <dbl> <dbl> <list>           
#1    10    10                  0     1 <tibble [81 × 4]>
#2    30    30                  0     1 <tibble [81 × 4]>
#3    50    50                  0     1 <tibble [81 × 4]>

注意:在这里,map因为我们需要两列“col”和“row”,所以不起作用。此外,lambda formap.x在遍历列之后

数据

 df_2 <- tibble::tibble(col = c(10, 30, 50),
                          row = c(10, 30, 50),
                          radius_from_center = rep(0, 3),
                          alpha = rep(1, 3))

推荐阅读