Skip to contents

The default output from an oa_fetch call is a tibble. This object type allows each row to be one unit of entity (article, institution, etc.), which is often helpful for downstream wrangling. It simplifies and combines complex output elements in list columns, which can be extracted or exploded with dplyr::rowwise or purrr::map.

IMPORTANT: in “flattening” the list output to a tibble, we have made a few decisions to simplify the original nested list such as retaining only one affiliation for each author if you’re querying Works (details in oa_df source code). While the tibble output is sufficient in most use cases, you may need to obtain the original nested list with all the information on an entity for your special research problem. If so, please specify output = "list" in your oa_fetch call.

Example 1: institutions

Suppose we queried Open Alex to obtain information on large Canadian institutions and now want to extract their latitudes and longitudes.

institutions <- oa_fetch(
  entity = "institutions",
  country_code = "CA",
  cited_by_count = ">4000000",
  verbose = TRUE,
  count_only = FALSE
)
#> Requesting url: https://api.openalex.org/institutions?filter=country_code%3ACA%2Ccited_by_count%3A%3E4000000
#> Getting 1 page of results with a total of 12 records...

head(institutions)
#> # A tibble: 6 × 22
#>   id          displ…¹ displ…² displ…³ inter…⁴ ror   ids      count…⁵ geo   type 
#>   <chr>       <chr>   <list>  <list>  <list>  <chr> <list>   <chr>   <lis> <chr>
#> 1 https://op… Univer… <lgl>   <lgl>   <df>    http… <tibble> CA      <df>  educ…
#> 2 https://op… Univer… <lgl>   <chr>   <df>    http… <tibble> CA      <df>  educ…
#> 3 https://op… McGill… <lgl>   <lgl>   <df>    http… <tibble> CA      <df>  educ…
#> 4 https://op… Univer… <chr>   <lgl>   <df>    http… <tibble> CA      <df>  educ…
#> 5 https://op… Univer… <lgl>   <chr>   <df>    http… <tibble> CA      <df>  educ…
#> 6 https://op… Univer… <chr>   <chr>   <df>    http… <tibble> CA      <df>  educ…
#> # … with 12 more variables: homepage_url <chr>, image_url <chr>,
#> #   image_thumbnail_url <chr>, associated_institutions <list>,
#> #   relevance_score <lgl>, works_count <int>, cited_by_count <int>,
#> #   counts_by_year <list>, works_api_url <chr>, x_concepts <list>,
#> #   updated_date <chr>, created_date <chr>, and abbreviated variable names
#> #   ¹​display_name, ²​display_name_alternatives, ³​display_name_acronyms,
#> #   ⁴​international, ⁵​country_code

We present three different approaches below.

dplyr::rowwise

The use of rowwise used to be discouraged, but the tidyverse team has now recognized its importance in many workflows, and so rowwise is here to stay. We think rowwise pairs very naturally with our list columns output.

institutions %>%
  rowwise() %>%
  mutate(
    name = display_name,
    openalex_id = stringr::str_extract(id, "I\\d+"),
    lat = geo$latitude,
    lon = geo$longitude,
    .keep = "none"
  )
#> # A tibble: 12 × 4
#> # Rowwise: 
#>    name                           openalex_id   lat    lon
#>    <chr>                          <chr>       <dbl>  <dbl>
#>  1 University of Toronto          I185261750   43.7  -79.4
#>  2 University of British Columbia I141945490   49.3 -123. 
#>  3 McGill University              I5023651     45.5  -73.6
#>  4 University of Alberta          I154425047   53.5 -114. 
#>  5 University of Calgary          I168635309   51.1 -114. 
#>  6 University of Waterloo         I151746483   43.5  -80.5
#>  7 Western University             I125749732   43.0  -81.3
#>  8 University of Ottawa           I153718931   45.4  -75.7
#>  9 University of Montreal         I70931966    45.5  -73.6
#> 10 McMaster University            I98251732    43.3  -79.9
#> 11 Université Laval               I43406934    46.8  -71.3
#> 12 Queen's University             I204722609   44.2  -76.5

purrr::map

Alternatively, you can use any function in the purrr::map family. As you can see below, the syntax is a little less natural, but you may gain some performance advantage if you have a really large dataframe.

institutions %>%
  mutate(
    name = display_name,
    openalex_id = stringr::str_extract(id, "I\\d+"),
    lat = purrr::map_dbl(geo, ~ .x$latitude),
    lon = purrr::map_dbl(geo, ~ .x$longitude),
    .keep = "none"
  )
#> # A tibble: 12 × 4
#>    name                           openalex_id   lat    lon
#>    <chr>                          <chr>       <dbl>  <dbl>
#>  1 University of Toronto          I185261750   43.7  -79.4
#>  2 University of British Columbia I141945490   49.3 -123. 
#>  3 McGill University              I5023651     45.5  -73.6
#>  4 University of Alberta          I154425047   53.5 -114. 
#>  5 University of Calgary          I168635309   51.1 -114. 
#>  6 University of Waterloo         I151746483   43.5  -80.5
#>  7 Western University             I125749732   43.0  -81.3
#>  8 University of Ottawa           I153718931   45.4  -75.7
#>  9 University of Montreal         I70931966    45.5  -73.6
#> 10 McMaster University            I98251732    43.3  -79.9
#> 11 Université Laval               I43406934    46.8  -71.3
#> 12 Queen's University             I204722609   44.2  -76.5

base::lapply

Similar to the purrr approach, you can use the base functions in the lapply family, for example:

institutions %>%
  mutate(
    name = display_name,
    openalex_id = stringr::str_extract(id, "I\\d+"),
    lat = vapply(geo, function(x) x$latitude, numeric(1)),
    lon = vapply(geo, function(x) x$longitude, numeric(1)),
    .keep = "none"
  )
#> # A tibble: 12 × 4
#>    name                           openalex_id   lat    lon
#>    <chr>                          <chr>       <dbl>  <dbl>
#>  1 University of Toronto          I185261750   43.7  -79.4
#>  2 University of British Columbia I141945490   49.3 -123. 
#>  3 McGill University              I5023651     45.5  -73.6
#>  4 University of Alberta          I154425047   53.5 -114. 
#>  5 University of Calgary          I168635309   51.1 -114. 
#>  6 University of Waterloo         I151746483   43.5  -80.5
#>  7 Western University             I125749732   43.0  -81.3
#>  8 University of Ottawa           I153718931   45.4  -75.7
#>  9 University of Montreal         I70931966    45.5  -73.6
#> 10 McMaster University            I98251732    43.3  -79.9
#> 11 Université Laval               I43406934    46.8  -71.3
#> 12 Queen's University             I204722609   44.2  -76.5

Example 2: works

Suppose we have a tibble of works output and would like to find the institutions corresponding with the works’ authors. In this case, each work may have more than one affiliated institutions.

Tibble output

Assuming that each author is affiliated with only one institution, we can call oa_fetch with the default output = "tibble":

works <- oa_fetch(
  entity = "works",
  title.search = c("bibliometric analysis", "science mapping"),
  cited_by_count = ">100",
  from_publication_date = "2020-01-01",
  to_publication_date = "2021-01-31",
  sort = "cited_by_count:desc",
  count_only = FALSE
)

We will store the result in a list column:

multi_insts <- works %>%
  rowwise() %>%
  mutate(
    openalex_id = stringr::str_extract(id, "W\\d+"),
    institutions = list(unique(author$institution_display_name)),
    .keep = "none"
  )

multi_insts
#> # A tibble: 13 × 2
#> # Rowwise: 
#>    openalex_id institutions
#>    <chr>       <list>      
#>  1 W3038273726 <chr [2]>   
#>  2 W2990450011 <chr [2]>   
#>  3 W3001491100 <chr [2]>   
#>  4 W3044902155 <chr [1]>   
#>  5 W3011866596 <chr [1]>   
#>  6 W3000049009 <lgl [1]>   
#>  7 W2990688366 <chr [3]>   
#>  8 W3000910650 <chr [3]>   
#>  9 W3042215340 <chr [3]>   
#> 10 W2986617680 <chr [2]>   
#> 11 W2999558594 <chr [2]>   
#> 12 W3038187379 <chr [10]>  
#> 13 W3025370095 <chr [4]>

# institutions of the first work
str(multi_insts[1, "institutions"])
#> rowws_df [1 × 1] (S3: rowwise_df/tbl_df/tbl/data.frame)
#>  $ institutions:List of 1
#>   ..$ : chr [1:2] "University of Southern Denmark" "BI Norwegian Business School"
#>  - attr(*, "groups")= tibble [1 × 1] (S3: tbl_df/tbl/data.frame)
#>   ..$ .rows: list<int> [1:1] 
#>   .. ..$ : int 1
#>   .. ..@ ptype: int(0)

List output

If we want to get all the institutions that the authors of these works are affiliated with (since one author may be affiliated with more than one institution), you would want to work with the list output.

As you can see, the nested list can be more convoluted to work with:

works_list <- oa_fetch(
  entity = "works",
  title.search = c("bibliometric analysis", "science mapping"),
  cited_by_count = ">100",
  from_publication_date = "2020-01-01",
  to_publication_date = "2021-01-31",
  sort = "cited_by_count:desc",
  output = "list"
)

work_authors <- lapply(works_list, \(x) x$author)

unique_insts <- sapply(
  work_authors,
  \(z) unique(unlist(
    sapply(
      z, \(y) sapply(y$institutions, \(x) x$display_name)
    )
  ))
)

unique_insts[[1]]
#> [1] "University of Southern Denmark" "BI Norwegian Business School"