Seurat Weekly NO.0 || 開刊詞

作為紀念開個專欄:每周精選Seurat社區有趣的問答以饗國內Seurat的用戶。

為什么要做這個事情呢?

  • 翻譯學習法
  • 認知學習法
  • 通勤學習法
  • 追蹤工具動態
  • 相信我,你并不孤獨

因為國內的單細胞數據分析人員越來越多,而Seurat為單細胞數據分析提供了一個很好的思考框架,當然Seurat發表的文章有很多。大家在應用這個單細胞數據分析工具的時候不免會遇到這樣或那樣的問題,這雖然是讓人苦惱的,但是以為偉人說過:好的問題要比好的答案價值百倍。于是,我在Seurat的github上watch了所有的問題,所以我的個人郵箱是這樣的:

所以在通勤路上看看大家都踩了Seurat的哪些坑,Seurat社區成員又是如何回復的,不能不說是一件有意思的事兒。何況還能學習一下英語啦_.

計劃是每周精選不多于10條的Issues,在翻譯和復現這些issue的時候也會摻雜一些自己對Seurat的學習心得,以促進Seurat學者了解這個項目。

目前github上面大部分的交流用的還是英語,我們為什么不用漢語在上面交流呢?那樣就達不到學習英語的目的了吧。

凡事善始者實繁,克終者蓋寡。Seurat Weekly能做幾期呢?我們不能承諾,畢竟是一項無人資助的事業,看緣分呢。

最為NO.0,今天主要探索一下選題與排版的一般規則。

選題的第一個規則就是某個話題出現的頻率,我們相信一個有很多人愿意討論的話題更大概率是一個好問題。其次是主編本人覺得有意思的問題。

至于排版,我們按照一般的FAQ的形式給出,問題部分我們給出原文描述,答案就是主編在看過別人的回答之后,夾雜著個人觀點的品論。

每個問題,我們也給出在github的鏈接,方便讀者朋友就原問題進行解答。

下面走幾個例子:

Getting parameters from pre-existing reduction (umap) (#3053)

github地址: https://github.com/satijalab/seurat/issues/3053

這位oh111 的意思應該是手里有了Seurat對象,想知道這個對象之前的作者是如何操作的。其實Seurat是給了每個操作過程的參數記錄的:

就拿我們seurat自帶的數據集來看吧:

Seurat::pbmc_small@commands

這返回的是一個list,他說想看PCA的參數,其實這樣就可以了:

Seurat::pbmc_small@commands$RunPCA.RNA
Command: RunPCA(object = pbmc_small, features = VariableFeatures(object = pbmc_small),     verbose = FALSE)
Time: 2018-08-28 04:34:56
assay : RNA 
features : PPBP IGLL5 VDAC3 CD1C AKR1C3 PF4 MYL9 GNLY TREML1 CA2 SDPR PGRMC1 S100A8 TUBB1 HLA-DQA1 PARVB RUFY1 HLA-DPB1 RP11-290F20.3 S100A9 
compute.dims : 20 
rev.pca : FALSE 
weight.by.var : TRUE 
verbose : FALSE 
print.dims : 1 2 3 4 5 
features.print : 30 
reduction.name : pca 
reduction.key : PC 
seed.use : 42 

Reorder cells by expression value in DoHeatmap & Dendogram (#3036)

github 地址:https://github.com/satijalab/seurat/issues/3036

這是一個可視化細節的問題,有時候我們用默認參數出來的圖并不能直接達到發表的水平,或者自己有些小心思想改一下這個圖,最常見的就是該標簽的順序。其實我們知道這個一般是通過因子變量的levels來控制的。

有位仁兄給出了這個鏈接: https://stackoverflow.com/questions/52136211/how-to-reorder-cells-in-doheatmap-plot-in-seurat-ggplot2

那么我們來看一下Seurat的繪圖是如何實現的,看DoHeatmapd的源代碼:

 DoHeatmap
function (object, features = NULL, cells = NULL, group.by = "ident", 
    group.bar = TRUE, group.colors = NULL, disp.min = -2.5, disp.max = NULL, 
    slot = "scale.data", assay = NULL, label = TRUE, size = 5.5, 
    hjust = 0, angle = 45, raster = TRUE, draw.lines = TRUE, 
    lines.width = NULL, group.bar.height = 0.02, combine = TRUE) 
{
    cells <- cells %||% colnames(x = object)
    if (is.numeric(x = cells)) {
        cells <- colnames(x = object)[cells]
    }
    assay <- assay %||% DefaultAssay(object = object)
    DefaultAssay(object = object) <- assay
    features <- features %||% VariableFeatures(object = object)
    features <- rev(x = unique(x = features))
    disp.max <- disp.max %||% ifelse(test = slot == "scale.data", 
        yes = 2.5, no = 6)
    possible.features <- rownames(x = GetAssayData(object = object, 
        slot = slot))
    if (any(!features %in% possible.features)) {
        bad.features <- features[!features %in% possible.features]
        features <- features[features %in% possible.features]
        if (length(x = features) == 0) {
            stop("No requested features found in the ", slot, 
                " slot for the ", assay, " assay.")
        }
        warning("The following features were omitted as they were not found in the ", 
            slot, " slot for the ", assay, " assay: ", paste(bad.features, 
                collapse = ", "))
    }
    data <- as.data.frame(x = as.matrix(x = t(x = GetAssayData(object = object, 
        slot = slot)[features, cells, drop = FALSE])))
    object <- suppressMessages(expr = StashIdent(object = object, 
        save.name = "ident"))
    group.by <- group.by %||% "ident"
    groups.use <- object[[group.by]][cells, , drop = FALSE]
    plots <- vector(mode = "list", length = ncol(x = groups.use))
    for (i in 1:ncol(x = groups.use)) {
        data.group <- data
        group.use <- groups.use[, i, drop = TRUE]
        if (!is.factor(x = group.use)) {
            group.use <- factor(x = group.use)
        }
        names(x = group.use) <- cells
        if (draw.lines) {
            lines.width <- lines.width %||% ceiling(x = nrow(x = data.group) * 
                0.0025)
            placeholder.cells <- sapply(X = 1:(length(x = levels(x = group.use)) * 
                lines.width), FUN = function(x) {
                return(RandomName(length = 20))
            })
            placeholder.groups <- rep(x = levels(x = group.use), 
                times = lines.width)
            group.levels <- levels(x = group.use)
            names(x = placeholder.groups) <- placeholder.cells
            group.use <- as.vector(x = group.use)
            names(x = group.use) <- cells
            group.use <- factor(x = c(group.use, placeholder.groups), 
                levels = group.levels)
            na.data.group <- matrix(data = NA, nrow = length(x = placeholder.cells), 
                ncol = ncol(x = data.group), dimnames = list(placeholder.cells, 
                  colnames(x = data.group)))
            data.group <- rbind(data.group, na.data.group)
        }
        lgroup <- length(levels(group.use))
        plot <- SingleRasterMap(data = data.group, raster = raster, 
            disp.min = disp.min, disp.max = disp.max, feature.order = features, 
            cell.order = names(x = sort(x = group.use)), group.by = group.use)
        if (group.bar) {
            default.colors <- c(hue_pal()(length(x = levels(x = group.use))))
            cols <- group.colors[1:length(x = levels(x = group.use))] %||% 
                default.colors
            if (any(is.na(x = cols))) {
                cols[is.na(x = cols)] <- default.colors[is.na(x = cols)]
                cols <- Col2Hex(cols)
                col.dups <- sort(x = unique(x = which(x = duplicated(x = substr(x = cols, 
                  start = 1, stop = 7)))))
                through <- length(x = default.colors)
                while (length(x = col.dups) > 0) {
                  pal.max <- length(x = col.dups) + through
                  cols.extra <- hue_pal()(pal.max)[(through + 
                    1):pal.max]
                  cols[col.dups] <- cols.extra
                  col.dups <- sort(x = unique(x = which(x = duplicated(x = substr(x = cols, 
                    start = 1, stop = 7)))))
                }
            }
            group.use2 <- sort(x = group.use)
            if (draw.lines) {
                na.group <- RandomName(length = 20)
                levels(x = group.use2) <- c(levels(x = group.use2), 
                  na.group)
                group.use2[placeholder.cells] <- na.group
                cols <- c(cols, "#FFFFFF")
            }
            pbuild <- ggplot_build(plot = plot)
            names(x = cols) <- levels(x = group.use2)
            y.range <- diff(x = pbuild$layout$panel_params[[1]]$y.range)
            y.pos <- max(pbuild$layout$panel_params[[1]]$y.range) + 
                y.range * 0.015
            y.max <- y.pos + group.bar.height * y.range
            plot <- plot + annotation_raster(raster = t(x = cols[group.use2]), 
                xmin = -Inf, xmax = Inf, ymin = y.pos, ymax = y.max) + 
                coord_cartesian(ylim = c(0, y.max), clip = "off") + 
                scale_color_manual(values = cols)
            if (label) {
                x.max <- max(pbuild$layout$panel_params[[1]]$x.range)
                x.divs <- pbuild$layout$panel_params[[1]]$x.major
                x <- data.frame(group = sort(x = group.use), 
                  x = x.divs)
                label.x.pos <- tapply(X = x$x, INDEX = x$group, 
                  FUN = median) * x.max
                label.x.pos <- data.frame(group = names(x = label.x.pos), 
                  label.x.pos)
                plot <- plot + geom_text(stat = "identity", data = label.x.pos, 
                  aes_string(label = "group", x = "label.x.pos"), 
                  y = y.max + y.max * 0.03 * 0.5, angle = angle, 
                  hjust = hjust, size = size)
                plot <- suppressMessages(plot + coord_cartesian(ylim = c(0, 
                  y.max + y.max * 0.002 * max(nchar(x = levels(x = group.use))) * 
                    size), clip = "off"))
            }
        }
        plot <- plot + theme(line = element_blank())
        plots[[i]] <- plot
    }
    if (combine) {
        plots <- CombinePlots(plots = plots)
    }
    return(plots)
}
<bytecode: 0x11837bb8>
<environment: namespace:Seurat>

我們發現Seurat的圖是用ggplot2實現的,這樣我們就可以基于函數的返回對象來用自己的ggplot功底修復了:

require(Seurat)
p <- DoHeatmap(pbmc_small)

p$theme
p$layers
p$mapping
 head(p$data)
        Feature           Cell Expression Identity
1        S100A9 ATGCCAGAACGACT -0.7639656        0
2 RP11-290F20.3 ATGCCAGAACGACT -0.3730316        0
3      HLA-DPB1 ATGCCAGAACGACT -1.0399941        0
4         RUFY1 ATGCCAGAACGACT -0.4098329        0
5         PARVB ATGCCAGAACGACT -0.3461794        0
6      HLA-DQA1 ATGCCAGAACGACT -0.6717070        0

Time series dataset in two conditions #3040

github 地址:https://github.com/satijalab/seurat/issues/3040

這是一個常見的問題,多個樣本在許多地方還是值得探討的,這位回答者直接給出了兩篇參考文獻:

I would recommend that you review the Guided tutorial, Multiple dataset integration (specifically the SCT method), and the Stimulated vs Control PBMCs, in that order. Due the large probable size of your final dataset, I think that the manipulations found within the Mouse Cell Atlas Vignette might also prove useful. The VIsualization and Cell cycle regression vignettes were also particularly helpful for our analysis of similar conditions. Lastly, I recommend that you review the methods in Farnsworth et al. 2020 as well as Soldatov et al., 2019 for further help. Hope that this was useful.

Optimal strategy to process samples to compare two different condition. (#3019)

這個其實和上個問題比較像,都是處理多個樣本,這里也有人士給出:

I wouldn't recommend using cellranger aggr as it will downsample everything to a similar number of counts as the sample with the lowest counts, and so potentially will throw out a lot of data. You could quantify each dataset (using cellranger, or another tool like Alevin) and first merge them in Seurat and check if there are batch differences between the datasets. If there are, you could run the integration methods

Deploying Shiny apps using Seurat library to shinyapps.io #2716

github 地址: https://github.com/satijalab/seurat/issues/2716

這是一類問題屬于對Seurat的擴展,這里是想把Seurat擴展到Shiny程序中,也就是給他界面化。這要求再開發者不單要對Seurat的函數和數據對象及其依賴的R包和環境有所了解,還要求他要懂得Shiny的語法和結構。其實這個問題下的討論多是想要彌補Seurat與Shiny的界限。

好了,今天就到這里,感謝大家的陪伴。對了,你在github上面提問了沒?

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,963評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,348評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,083評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,706評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,442評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,802評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,795評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,983評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,542評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,287評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,486評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,030評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,710評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,116評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,412評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,224評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,462評論 2 378