Skip to content
This repository was archived by the owner on Oct 14, 2025. It is now read-only.

Commit a58b669

Browse files
authored
Merge pull request #99 from stemangiola/unharmonised-v2
Implementation of the new suggested unharmonised API
2 parents 98748c9 + e0f2a8d commit a58b669

File tree

9 files changed

+269
-168
lines changed

9 files changed

+269
-168
lines changed

NAMESPACE

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,16 @@ importFrom(cli,cli_abort)
2525
importFrom(cli,cli_alert_info)
2626
importFrom(cli,cli_alert_success)
2727
importFrom(cli,cli_alert_warning)
28+
importFrom(dbplyr,remote_con)
2829
importFrom(dplyr,as_tibble)
2930
importFrom(dplyr,collect)
3031
importFrom(dplyr,filter)
3132
importFrom(dplyr,full_join)
33+
importFrom(dplyr,group_by)
3234
importFrom(dplyr,inner_join)
3335
importFrom(dplyr,mutate)
3436
importFrom(dplyr,pull)
37+
importFrom(dplyr,summarise)
3538
importFrom(dplyr,tbl)
3639
importFrom(dplyr,tibble)
3740
importFrom(dplyr,transmute)

R/query.R

Lines changed: 0 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -448,52 +448,3 @@ get_metadata <- function(
448448
dbConnect(drv = _, read_only = TRUE) |>
449449
tbl(db_path)
450450
}
451-
452-
#' Returns unharmonised metadata for selected datasets.
453-
#'
454-
#' Various metadata fields are *not* common between datasets, so it does not
455-
#' make sense for these to live in the main metadata table. This function is a
456-
#' utility that allows easy fetching of this data if necessary.
457-
#'
458-
#' @param dataset_ids A character vector, where each entry is a dataset ID
459-
#' obtained from the `$file_id` column of the table returned from
460-
#' [get_metadata()]
461-
#' @param remote_url Optional character vector of length 1. An HTTP URL pointing
462-
#' to the root URL under which all the unharmonised dataset files are located.
463-
#' @param cache_directory Optional character vector of length 1. A file path on
464-
#' your local system to a directory (not a file) that will be used to store
465-
#' the unharmonised metadata files.
466-
#' @importFrom purrr map set_names
467-
#' @importFrom glue glue
468-
#' @importFrom DBI dbConnect
469-
#' @importFrom duckdb duckdb
470-
#' @importFrom dplyr tbl
471-
#' @return A named list, where each name is a dataset file ID, and each value is
472-
#' a "lazy data frame", ie a `tbl`.
473-
#' @export
474-
#' @examples
475-
#' dataset = "838ea006-2369-4e2c-b426-b2a744a2b02b"
476-
#' harmonised_meta = get_metadata() |> dplyr::filter(file_id == dataset) |> dplyr::collect()
477-
#' unharmonised_meta = get_unharmonised_metadata(dataset)
478-
#' unharmonised_tbl = dplyr::collect(unharmonised_meta[[dataset]])
479-
#' dplyr::left_join(harmonised_meta, unharmonised_tbl, by=c("file_id", "cell_"))
480-
get_unharmonised_metadata = function(
481-
dataset_ids,
482-
remote_url = "https://object-store.rc.nectar.org.au/v1/AUTH_06d6e008e3e642da99d806ba3ea629c5/unharmonised_metadata",
483-
cache_directory = get_default_cache_dir()
484-
){
485-
unharmonised_root <- file.path(cache_directory, COUNTS_VERSION, "unharmonised")
486-
duck = duckdb() |> dbConnect(drv = _, read_only = TRUE)
487-
dataset_ids |>
488-
set_names() |>
489-
map(function(dataset_id){
490-
file_name = glue::glue("{dataset_id}.parquet")
491-
local_path = file.path(unharmonised_root, file_name)
492-
glue("{remote_url}/{file_name}") |>
493-
sync_remote_file(
494-
local_path,
495-
progress(type = "down", con = stderr())
496-
)
497-
tbl(duck, local_path)
498-
})
499-
}

R/unharmonised.R

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#' Returns unharmonised metadata for selected datasets.
2+
#'
3+
#' Various metadata fields are *not* common between datasets, so it does not
4+
#' make sense for these to live in the main metadata table. This function is a
5+
#' utility that allows easy fetching of this data if necessary.
6+
#'
7+
#' @param dataset_id A character vector, where each entry is a dataset ID
8+
#' obtained from the `$file_id` column of the table returned from
9+
#' [get_metadata()]
10+
#' @param cells An optional character vector of cell IDs. If provided, only
11+
#' metadata for those cells will be returned.
12+
#' @param conn An optional DuckDB connection object. If provided, it will re-use
13+
#' the existing connection instead of opening a new one.
14+
#' @param remote_url Optional character vector of length 1. An HTTP URL pointing
15+
#' to the root URL under which all the unharmonised dataset files are located.
16+
#' @param cache_directory Optional character vector of length 1. A file path on
17+
#' your local system to a directory (not a file) that will be used to store
18+
#' the unharmonised metadata files.
19+
#' @importFrom purrr map set_names
20+
#' @importFrom glue glue
21+
#' @importFrom DBI dbConnect
22+
#' @importFrom duckdb duckdb
23+
#' @importFrom dplyr tbl filter
24+
#' @importFrom rlang .data
25+
#' @return A named list, where each name is a dataset file ID, and each value is
26+
#' a "lazy data frame", ie a `tbl`.
27+
#' @examples
28+
#' \dontrun{
29+
#' dataset = "838ea006-2369-4e2c-b426-b2a744a2b02b"
30+
#' harmonised_meta = get_metadata() |> dplyr::filter(file_id == dataset) |> dplyr::collect()
31+
#' unharmonised_meta = get_unharmonised_dataset(dataset)
32+
#' unharmonised_tbl = dplyr::collect(unharmonised_meta[[dataset]])
33+
#' dplyr::left_join(harmonised_meta, unharmonised_tbl, by=c("file_id", "cell_"))
34+
#' }
35+
get_unharmonised_dataset = function(
36+
dataset_id,
37+
cells = NULL,
38+
conn = duckdb() |> dbConnect(drv = _, read_only = TRUE),
39+
remote_url = "https://object-store.rc.nectar.org.au/v1/AUTH_06d6e008e3e642da99d806ba3ea629c5/unharmonised_metadata",
40+
cache_directory = get_default_cache_dir()
41+
){
42+
unharmonised_root <- file.path(cache_directory, COUNTS_VERSION, "unharmonised")
43+
file_name = glue::glue("{dataset_id}.parquet")
44+
local_path = file.path(unharmonised_root, file_name)
45+
glue("{remote_url}/{file_name}") |>
46+
sync_remote_file(
47+
local_path,
48+
progress(type = "down", con = stderr())
49+
)
50+
tbl(conn, local_path) |>
51+
filter(.data$cell_ %in% cells)
52+
}
53+
54+
#' Returns unharmonised metadata for a metadata query
55+
#' @inherit get_unharmonised_dataset description
56+
#' @param metadata A lazy data frame obtained from [get_metadata()], filtered
57+
#' down to some cells of interest
58+
#' @inheritDotParams get_unharmonised_dataset
59+
#' @return A tibble with two columns:
60+
#' * `file_id`: the same `file_id` as the main metadata table obtained from [get_metadata()]
61+
#' * `unharmonised`: a nested tibble, with one row per cell in the input `metadata`, containing unharmonised metadata
62+
#' @export
63+
#' @importFrom dplyr group_by summarise filter collect
64+
#' @importFrom rlang .data
65+
#' @importFrom dbplyr remote_con
66+
#' @examples
67+
#' harmonised <- get_metadata() |> dplyr::filter(tissue == "kidney blood vessel")
68+
#' unharmonised <- get_unharmonised_metadata(harmonised)
69+
get_unharmonised_metadata = function(metadata, ...){
70+
args = list(...)
71+
metadata |>
72+
collect() |>
73+
group_by(.data$file_id) |>
74+
summarise(
75+
unharmonised = list(
76+
dataset_id=.data$file_id[[1]],
77+
cells=.data$cell_,
78+
conn=remote_con(metadata)
79+
) |>
80+
c(args) |>
81+
do.call(get_unharmonised_dataset, args=_) |>
82+
list()
83+
)
84+
}

README.Rmd

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -279,26 +279,22 @@ knitr::include_graphics("man/figures/HLA_A_tissue_plot.png")
279279

280280
Various metadata fields are *not* common between datasets, so it does not
281281
make sense for these to live in the main metadata table. However, we can
282-
obtain it using the `get_unharmonised_metadata()` function.
283-
284-
Note how this table has additional columns that are not in the normal metadata:
282+
obtain it using the `get_unharmonised_metadata()` function. This function
283+
returns a data frame with one row per dataset, including the `unharmonised`
284+
column which contains unharmnised metadata as a nested data frame.
285285

286286
```{r}
287-
dataset = "838ea006-2369-4e2c-b426-b2a744a2b02b"
288-
unharmonised_meta = get_unharmonised_metadata(dataset)
289-
unharmonised_tbl = dplyr::collect(unharmonised_meta[[dataset]])
290-
unharmonised_tbl
287+
harmonised <- get_metadata() |> dplyr::filter(tissue == "kidney blood vessel")
288+
unharmonised <- get_unharmonised_metadata(harmonised)
289+
unharmonised
291290
```
292291

293-
If we have metadata from the normal metadata table that is from a single dataset,
294-
we can even join this additional metadata into one big data frame:
292+
Notice that the columns differ between each dataset's data frame:
293+
295294
```{r}
296-
harmonised_meta = get_metadata() |> dplyr::filter(file_id == dataset) |> dplyr::collect()
297-
dplyr::left_join(harmonised_meta, unharmonised_tbl, by=c("file_id", "cell_"))
295+
dplyr::pull(unharmonised, unharmonised) |> head(2)
298296
```
299297

300-
301-
302298
# Cell metadata
303299

304300
Dataset-specific columns (definitions available at cellxgene.cziscience.com)

README.md

Lines changed: 68 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -70,18 +70,18 @@ metadata |>
7070
dplyr::count(tissue)
7171
#> # Source: SQL [?? x 2]
7272
#> # Database: DuckDB 0.6.2-dev1166 [unknown@Linux 3.10.0-1160.81.1.el7.x86_64:R 4.2.1/:memory:]
73-
#> tissue n
74-
#> <chr> <dbl>
75-
#> 1 blood 47
76-
#> 2 respiratory airway 16
77-
#> 3 mammary gland epithelial cell (cell culture) 1
78-
#> 4 colon 3
79-
#> 5 intestine 18
80-
#> 6 pleural effusion 11
81-
#> 7 lymph node 15
82-
#> 8 lung 27
83-
#> 9 liver 24
84-
#> 10 axilla 10
73+
#> tissue n
74+
#> <chr> <dbl>
75+
#> 1 cerebellum 3
76+
#> 2 telencephalon 2
77+
#> 3 heart 3
78+
#> 4 intestine 18
79+
#> 5 kidney 19
80+
#> 6 liver 24
81+
#> 7 lung 27
82+
#> 8 muscle organ 3
83+
#> 9 pancreas 5
84+
#> 10 placenta 3
8585
#> # … with more rows
8686
```
8787

@@ -294,65 +294,68 @@ metadata |>
294294

295295
Various metadata fields are *not* common between datasets, so it does
296296
not make sense for these to live in the main metadata table. However, we
297-
can obtain it using the `get_unharmonised_metadata()` function.
298-
299-
Note how this table has additional columns that are not in the normal
300-
metadata:
297+
can obtain it using the `get_unharmonised_metadata()` function. This
298+
function returns a data frame with one row per dataset, including the
299+
`unharmonised` column which contains unharmnised metadata as a nested
300+
data frame.
301301

302302
``` r
303-
dataset = "838ea006-2369-4e2c-b426-b2a744a2b02b"
304-
unharmonised_meta = get_unharmonised_metadata(dataset)
305-
unharmonised_tbl = dplyr::collect(unharmonised_meta[[dataset]])
306-
unharmonised_tbl
307-
#> # A tibble: 168,860 × 23
308-
#> cell_ file_id Neuro…¹ Class Subcl…² Super…³ Age.a…⁴ Years…⁵ Cogni…⁶ ADNC
309-
#> <chr> <chr> <lgl> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
310-
#> 1 GGACGAAG… 838ea0… FALSE Neur… L4 IT L4 IT_2 90+ ye… 16 to … Dement… High
311-
#> 2 TCACGGGA… 838ea0… FALSE Neur… L4 IT L4 IT_1 90+ ye… 12 to … Dement… Inte…
312-
#> 3 TCAGTTTT… 838ea0… FALSE Neur… L4 IT L4 IT_2 78 to … 16 to … No dem… Low
313-
#> 4 TCAGTCCT… 838ea0… FALSE Neur… L4 IT L4 IT_4 78 to … 16 to … Dement… Inte…
314-
#> 5 AGCCACGC… 838ea0… FALSE Neur… L4 IT L4 IT_2 78 to … 19 to … No dem… Inte…
315-
#> 6 CCTCAACC… 838ea0… TRUE Neur… L4 IT L4 IT_2 Less t… Refere… Refere… Refe…
316-
#> 7 CTCGACAA… 838ea0… FALSE Neur… L4 IT L4 IT_2 78 to … 12 to … No dem… Inte…
317-
#> 8 AGCTACAG… 838ea0… FALSE Neur… L4 IT L4 IT_4 90+ ye… 16 to … Dement… High
318-
#> 9 CTCGAGGG… 838ea0… FALSE Neur… L4 IT L4 IT_2 65 to … 16 to … Dement… High
319-
#> 10 AGTGCCGT… 838ea0… FALSE Neur… L4 IT L4 IT_4 90+ ye… 16 to … Dement… High
320-
#> # … with 168,850 more rows, 13 more variables: Braak.stage <chr>,
321-
#> # Thal.phase <chr>, CERAD.score <chr>, APOE4.status <chr>,
322-
#> # Lewy.body.disease.pathology <chr>, LATE.NC.stage <chr>,
323-
#> # Microinfarct.pathology <chr>, Specimen.ID <chr>, Donor.ID <chr>, PMI <chr>,
324-
#> # Number.of.UMIs <dbl>, Genes.detected <dbl>,
325-
#> # Fraction.mitochrondrial.UMIs <dbl>, and abbreviated variable names
326-
#> # ¹​Neurotypical.reference, ²​Subclass, ³​Supertype, ⁴​Age.at.death, …
303+
harmonised <- get_metadata() |> dplyr::filter(tissue == "kidney blood vessel")
304+
unharmonised <- get_unharmonised_metadata(harmonised)
305+
unharmonised
306+
#> # A tibble: 4 × 2
307+
#> file_id unharmonised
308+
#> <chr> <list>
309+
#> 1 63523aa3-0d04-4fc6-ac59-5cadd3e73a14 <tbl_dck_[,17]>
310+
#> 2 8fee7b82-178b-4c04-bf23-04689415690d <tbl_dck_[,12]>
311+
#> 3 dc9d8cdd-29ee-4c44-830c-6559cb3d0af6 <tbl_dck_[,14]>
312+
#> 4 f7e94dbb-8638-4616-aaf9-16e2212c369f <tbl_dck_[,14]>
327313
```
328314

329-
If we have metadata from the normal metadata table that is from a single
330-
dataset, we can even join this additional metadata into one big data
331-
frame:
315+
Notice that the columns differ between each dataset’s data frame:
332316

333317
``` r
334-
harmonised_meta = get_metadata() |> dplyr::filter(file_id == dataset) |> dplyr::collect()
335-
dplyr::left_join(harmonised_meta, unharmonised_tbl, by=c("file_id", "cell_"))
336-
#> # A tibble: 168,860 × 77
337-
#> cell_ sample_ cell_…¹ cell_…² confi…³ cell_…⁴ cell_…⁵ cell_…⁶ sampl…⁷ _samp…⁸
338-
#> <chr> <chr> <chr> <chr> <dbl> <chr> <chr> <chr> <chr> <chr>
339-
#> 1 GGAC… f63cb4… L2/3-6… neuron 1 <NA> <NA> <NA> 168593… H21.33…
340-
#> 2 TCAC… 0d4d1f… L2/3-6… neuron 1 <NA> <NA> <NA> f7d747… H21.33…
341-
#> 3 TCAG… 3e5a3b… L2/3-6… neuron 1 <NA> <NA> <NA> 3417a9… H20.33…
342-
#> 4 TCAG… 7010a3… L2/3-6… neuron 1 <NA> <NA> <NA> 246a59… H20.33…
343-
#> 5 AGCC… 82bb9a… L2/3-6… neuron 1 <NA> <NA> <NA> 7a8f35… H21.33…
344-
#> 6 CCTC… a233eb… L2/3-6… neuron 1 <NA> <NA> <NA> 188243… H18.30…
345-
#> 7 CTCG… 27f104… L2/3-6… neuron 1 <NA> <NA> <NA> a62943… H20.33…
346-
#> 8 AGCT… 0190a2… L2/3-6… neuron 1 <NA> <NA> <NA> c508a8… H20.33…
347-
#> 9 CTCG… 95d846… L2/3-6… neuron 1 <NA> <NA> <NA> 29285d… H21.33…
348-
#> 10 AGTG… b0e1c5… L2/3-6… neuron 1 <NA> <NA> <NA> cd7823… H21.33…
349-
#> # … with 168,850 more rows, 67 more variables: assay <chr>,
350-
#> # assay_ontology_term_id <chr>, file_id_db <chr>,
351-
#> # cell_type_ontology_term_id <chr>, development_stage <chr>,
352-
#> # development_stage_ontology_term_id <chr>, disease <chr>,
353-
#> # disease_ontology_term_id <chr>, ethnicity <chr>,
354-
#> # ethnicity_ontology_term_id <chr>, experiment___ <chr>, file_id <chr>,
355-
#> # is_primary_data_x <chr>, organism <chr>, organism_ontology_term_id <chr>, …
318+
dplyr::pull(unharmonised, unharmonised) |> head(2)
319+
#> [[1]]
320+
#> # Source: SQL [?? x 17]
321+
#> # Database: DuckDB 0.6.2-dev1166 [unknown@Linux 3.10.0-1160.81.1.el7.x86_64:R 4.2.1/:memory:]
322+
#> cell_ file_id donor…¹ donor…² libra…³ mappe…⁴ sampl…⁵ suspe…⁶ suspe…⁷ autho…⁸
323+
#> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
324+
#> 1 4602… 63523a… 27 mon… a8536b… 5ddaea… GENCOD… 61bf84… cell d8a44f… Pelvic…
325+
#> 2 4602… 63523a… 27 mon… a8536b… 5ddaea… GENCOD… 61bf84… cell d8a44f… Pelvic…
326+
#> 3 4602… 63523a… 27 mon… a8536b… 5ddaea… GENCOD… 61bf84… cell d8a44f… Pelvic…
327+
#> 4 4602… 63523a… 27 mon… a8536b… 5ddaea… GENCOD… 61bf84… cell d8a44f… Pelvic…
328+
#> 5 4602… 63523a… 27 mon… a8536b… 5ddaea… GENCOD… 61bf84… cell d8a44f… Pelvic…
329+
#> 6 4602… 63523a… 27 mon… a8536b… 5ddaea… GENCOD… 61bf84… cell d8a44f… Pelvic…
330+
#> 7 4602… 63523a… 27 mon… a8536b… 5ddaea… GENCOD… 61bf84… cell d8a44f… Pelvic…
331+
#> 8 4602… 63523a… 27 mon… a8536b… 5ddaea… GENCOD… 61bf84… cell d8a44f… Pelvic…
332+
#> 9 4602… 63523a… 19 mon… 463181… 671785… GENCOD… 125234… cell c7485e… CD4 T …
333+
#> 10 4602… 63523a… 27 mon… a8536b… 5ddaea… GENCOD… 61bf84… cell d8a44f… Pelvic…
334+
#> # … with more rows, 7 more variables: cell_state <chr>,
335+
#> # reported_diseases <chr>, Short_Sample <chr>, Project <chr>,
336+
#> # Experiment <chr>, compartment <chr>, broad_celltype <chr>, and abbreviated
337+
#> # variable names ¹​donor_age, ²​donor_uuid, ³​library_uuid,
338+
#> # ⁴​mapped_reference_annotation, ⁵​sample_uuid, ⁶​suspension_type,
339+
#> # ⁷​suspension_uuid, ⁸​author_cell_type
340+
#>
341+
#> [[2]]
342+
#> # Source: SQL [?? x 12]
343+
#> # Database: DuckDB 0.6.2-dev1166 [unknown@Linux 3.10.0-1160.81.1.el7.x86_64:R 4.2.1/:memory:]
344+
#> cell_ file_id orig.…¹ nCoun…² nFeat…³ seura…⁴ Project donor…⁵ compa…⁶ broad…⁷
345+
#> <chr> <chr> <chr> <dbl> <chr> <chr> <chr> <chr> <chr> <chr>
346+
#> 1 1069 8fee7b… 4602ST… 16082 3997 25 Experi… Wilms3 non_PT Pelvic…
347+
#> 2 1214 8fee7b… 4602ST… 1037 606 25 Experi… Wilms3 non_PT Pelvic…
348+
#> 3 2583 8fee7b… 4602ST… 3028 1361 25 Experi… Wilms3 non_PT Pelvic…
349+
#> 4 2655 8fee7b… 4602ST… 1605 859 25 Experi… Wilms3 non_PT Pelvic…
350+
#> 5 3609 8fee7b… 4602ST… 1144 682 25 Experi… Wilms3 non_PT Pelvic…
351+
#> 6 3624 8fee7b… 4602ST… 1874 963 25 Experi… Wilms3 non_PT Pelvic…
352+
#> 7 3946 8fee7b… 4602ST… 1296 755 25 Experi… Wilms3 non_PT Pelvic…
353+
#> 8 5163 8fee7b… 4602ST… 11417 3255 25 Experi… Wilms3 non_PT Pelvic…
354+
#> 9 5446 8fee7b… 4602ST… 1769 946 19 Experi… Wilms2 lympho… CD4 T …
355+
#> 10 6275 8fee7b… 4602ST… 3750 1559 25 Experi… Wilms3 non_PT Pelvic…
356+
#> # … with more rows, 2 more variables: author_cell_type <chr>, Sample <chr>, and
357+
#> # abbreviated variable names ¹​orig.ident, ²​nCount_RNA, ³​nFeature_RNA,
358+
#> # ⁴​seurat_clusters, ⁵​donor_id, ⁶​compartment, ⁷​broad_celltype
356359
```
357360

358361
# Cell metadata

man/get_unharmonised_dataset.Rd

Lines changed: 51 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)