Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tibble() behaves oddly with classed list columns #1541

Open
moodymudskipper opened this issue Apr 28, 2023 · 0 comments
Open

tibble() behaves oddly with classed list columns #1541

moodymudskipper opened this issue Apr 28, 2023 · 0 comments

Comments

@moodymudskipper
Copy link

moodymudskipper commented Apr 28, 2023

# I can't define this object
# https://stackoverflow.com/questions/54734771/sf-write-lat-long-from-geometry-into-separate-column-and-keep-id-column
fun <- function() {
  tibble::tibble(
  ID = c(1, 2, 4),
  geometry = list(
    c(117.2, 31.8) |>
      structure(class = c("XY", "POINT", "sfg")),
    c(116.4, 40.1) |>
      structure(class = c("XY", "POINT", "sfg")),
    c(117.9, 26) |>
      structure(class = c("XY", "POINT", "sfg"))
  ) |>
    structure(
      class = c("sfc_POINT", "sfc"),
      precision = 0,
      bbox = c(xmin = 116.4, ymin = 26, xmax = 117.9, ymax = 40.1) |>
        structure(class = "bbox"),
      crs = list(epsg = 4326L, proj4string = "+proj=longlat +datum=WGS84 +no_defs") |>
        structure(class = "crs"),
      n_empty = 0L
    ),
) |>
  structure(
    class = c("sf", "tbl_df", "tbl", "data.frame"),
    sf_column = "geometry",
    agr = factor(c(ID = NA_character_), levels = c("constant", "aggregate", "identity"))
  )
}

fun()
#> Error in `tibble::tibble()`:
#> ! All columns in a tibble must be vectors.
#> ✖ Column `geometry` is a `sfc_POINT/sfc` object.

# but it works if I load sf's namespace, despite it not changing the vector quality of the column
loadNamespace("sf")
#> <environment: namespace:sf>
fun()

#> Simple feature collection with 3 features and 1 field
#> Geometry type: POINT
#> Dimension:     XY
#> Bounding box:  xmin: 116.4 ymin: 26 xmax: 117.9 ymax: 40.1
#> old-style crs object detected; please recreate object with a recent sf::st_crs()
#> Geodetic CRS:  WGS 84
#> old-style crs object detected; please recreate object with a recent sf::st_crs()
#> # A tibble: 3 × 2
#>      ID     geometry
#> * <dbl>  <POINT [°]>
#> 1     1 (117.2 31.8)
#> 2     2 (116.4 40.1)
#> 3     4   (117.9 26)

# simpler example, tibble won't support list columns of any class
b <- structure(list(letters), class= "foo")

tibble::tibble(A = 1, B = b)
#> Error in `tibble::tibble()`:
#> ! All columns in a tibble must be vectors.
#> ✖ Column `B` is a `foo` object.

# That works if I use I() as in base R
tibble::tibble(A = 1, B = I(b))
#> # A tibble: 1 × 2
#>       A B         
#>   <dbl> <I<list>> 
#> 1     1 <chr [26]>

# I could define it with structure() but it won't print
df2 <- structure(list(A=1, B=b), class = c("tbl_df", "tbl", "data.frame"))
df2
#> Error in `[<-`:
#> ! Assigned data `map(.subset(x, unname), vectbl_set_names, NULL)` must
#>   be a vector.
#> Caused by error in `vec_size()`:
#> ! `x` must be a vector, not a <foo> object.

Is there a good reason to refuse classed list columns by default ? Is this something relating to subsetting or length methods ? My feeling is that {tibble} should use implementation wise subsetting and length (e.g. .subset2
rather than [[.foo), so that the object wouldn't depend on which packages are loaded, and the class shouldn't be a problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant