seurat-disk icon indicating copy to clipboard operation
seurat-disk copied to clipboard

Missing meidum_umi in SCTModel obj - backward compatibility

Open simoncmo opened this issue 3 years ago • 5 comments

TL;DR: New slot "median_umi" in the SCTModel is causing issues when converting Seurat obj to anndata likely due to a different Suerat version. Could you perhaps add support to handle the missing slot? Thanks!

Hi I ran into an issue when running SaveH5Seurat It always stopped when trying to convert the SCT object in Seurat object

Creating h5Seurat file for version 3.1.5.9900
Adding counts for Spatial
Adding data for Spatial
No variable features found for Spatial
No feature-level metadata found for Spatial
Adding counts for SCT
Adding data for SCT
Adding scale.data for SCT
Adding variable features for SCT
Error in slot(object = object, name = x) : 
  no slot of name "median_umi" for this object of class "SCTModel"

Note: Though when I run Version() on the object it says 4.0.2, SCTransfrom might be run on the older version

After spending time on investigation, it seems like it's SCTModel object in SCTModel.list slot of SCT assay obj is causing the issue

The newer class definition of this object added a new slot median_umi but not in the older one The slot for the older one is just shown as NA. A similar error message comes up when using str as below

[email protected][[1]] %>% str(max.level = 2)
Formal class 'SCTModel' [package "Seurat"] with 7 slots
  ..@ feature.attributes:'data.frame':  17062 obs. of  12 variables:
  ..@ cell.attributes   :'data.frame':  0 obs. of  3 variables:
  ..@ clips             :List of 2
  ..@ umi.assay         : chr "Spatial"
  ..@ model             : chr "y ~ log_umi"
  ..@ arguments         :List of 25
  ..@ NA                : NULL
Warning message:
Not a validObject(): no slot of name "median_umi" for this object of class "SCTModel"

while can see it's expecting median_umi using slotNames

> slotNames([email protected][[1]])
[1] "feature.attributes" "cell.attributes"    "clips"             
[4] "umi.assay"          "model"              "arguments"         
[7] "median_umi"   

Checking https://github.com/satijalab/seurat/blob/master/R/objects.R I can see its defined here

median_umi <- NA
  # check if a custom scale_factor was provided to vst()
  if ("scale_factor" %in% names(vst.res$arguments)){
    median_umi <- vst.res$arguments$scale_factor
  }
  if (is.na(median_umi)) {
    if ("umi" %in% colnames(x = cell.attrs)) {
      median_umi <- median(cell.attrs$umi)
    } else if ("log_umi" %in% colnames(x = cell.attrs)) {
      median_umi <- median(10 ^ cell.attrs$log_umi)
    }
  }
  vst.res.SCTModel  <- SCTModel(
    feature.attributes = feature.attrs,
    cell.attributes = cell.attrs,
    clips = clips,
    umi.assay = vst.res$umi.assay %||% "RNA",
    model =  vst.res$model_str,
    arguments =  vst.res$arguments,
    median_umi = median_umi
  )
  return(vst.res.SCTModel)

At the moment the ad-hoc solution is do calculation of this number and assign to it manually slot([email protected][[1]], 'median_umi') = median([email protected][[1]]@cell.attributes$umi)

Was hoping there's a formal implementation of this to overcome this issue likely from the new versioning of the Seurat object.

Thanks!

simoncmo avatar Jan 24 '22 20:01 simoncmo

Thanks for posting this workaround. I encountered this issue as well and added the median_umi slot as you suggested. For some reason I still ran into the same error, even though the slot was populated based on [email protected][[1]] %>% str(max.level = 2). My object also gave No variable features found for SCT and No feature-level metadata found for SCT during the conversion, so perhaps the difference lies somewhere there.

In the end, my workaround was to regenerate the Seurat object with a more recent Seurat (v4.1.0), which populated the median_umi slot and underwent the conversion. Would be great if there were an option to bypass this error for those who cannot regenerate the original object.

yoda-vid avatar Apr 29 '22 03:04 yoda-vid

Thanks for this! Works great! @yoda-vid If you have multiple SCTModels in your SCTModel.list you need to apply this fix to all of them, not just the first entry. Check by running [email protected].

koenprange avatar Dec 05 '22 14:12 koenprange

Hi. I'm also running into this error when trying to run PrepSCTFindMarkers() on a merged object.

merged_diffEx <- PrepSCTFindMarkers(merged_diffEx, assay = "SCT", verbose = TRUE)
Error in slot(object = object, name = slot) : 
  no slot of name "median_umi" for this object of class "SCTModel"

The difference is, when I run the checks in previous posts I see that I have a value for median_umi. I even tried manually assigning/overwriting the medians already present, but that did not fix. Any ideas on why the median_umi isn't being recognized and/or how to fix? Thank you!

These are the commands I ran:

[email protected]
$model1
An sctransform model.
  Model formula:  y ~ log_umi 
  Parameters stored for 15304 features, 1668 cells.

$model1.1
An sctransform model.
  Model formula:  y ~ log_umi 
  Parameters stored for 15167 features, 1527 cells.
slotNames([email protected][[1]])
[1] "feature.attributes" "cell.attributes"    "clips"              "umi.assay"          "model"             
[6] "arguments"          "median_umi"   
slotNames([email protected][[1.1]])
[1] "feature.attributes" "cell.attributes"    "clips"              "umi.assay"          "model"             
[6] "arguments"          "median_umi"   
[email protected][[1]] %>% str(max.level = 2)
Formal class 'SCTModel' [package "Seurat"] with 7 slots
  ..@ feature.attributes:'data.frame':	15304 obs. of  12 variables:
  ..@ cell.attributes   :'data.frame':	1668 obs. of  3 variables:
  ..@ clips             :List of 2
  ..@ umi.assay         : chr "spatial"
  ..@ model             : chr "y ~ log_umi"
  ..@ arguments         :List of 32
  ..@ median_umi        : num 48622
[email protected][[1.1]] %>% str(max.level = 2)
Formal class 'SCTModel' [package "Seurat"] with 7 slots
  ..@ feature.attributes:'data.frame':	15304 obs. of  12 variables:
  ..@ cell.attributes   :'data.frame':	1668 obs. of  3 variables:
  ..@ clips             :List of 2
  ..@ umi.assay         : chr "spatial"
  ..@ model             : chr "y ~ log_umi"
  ..@ arguments         :List of 32
  ..@ median_umi        : num 48622

I also found a third(?) model, when I should only have 2 (I added this median umi manually with above workaround):

[email protected][[2]] %>% str(max.level = 2)
Formal class 'SCTModel' [package "Seurat"] with 7 slots
  ..@ feature.attributes:'data.frame':	15167 obs. of  12 variables:
  ..@ cell.attributes   :'data.frame':	1527 obs. of  3 variables:
  ..@ clips             :List of 2
  ..@ umi.assay         : chr "Spatial"
  ..@ model             : chr "y ~ log_umi"
  ..@ arguments         :List of 32
  ..@ median_umi        : num 34132

satkinson0115 avatar Apr 27 '23 19:04 satkinson0115

I also encountered the same error when exporting an integrated object (integrated via the SCT method). Can confirm that @simoncmo 's solution works without issue! Note that in this case it has to be applied recursively to all entries in the SCTModel list for both the SCT and integrated assay.

FerranC96 avatar Jun 02 '23 13:06 FerranC96

Glad this is helpful for people. Was thinking this issue would have been addressed after a while so didn't post, but I end up writing a few functions to check/clean and fill in the that slot back then. Feel free to give it a try if it helps. https://github.com/simoncmo/shared_seurat_scripts/blob/main/function_seurat_janitor.R

Just simply called FixSeuratSCT(seurat_obj) should check on all SCT Models, it will

  • remove empty SCT Models by checking if cell.attributes slot is empty
  • fill in medium_umi count

Hi @satkinson0115, its been a while hope you fixed that already, looking at your script I noticed you get the first model twice [email protected][[1]] and [email protected][[1.1]] both retrieved the same SCT Model object : [email protected][['model1']] you can verify this by observing at that the size and other values of all the slots are the same.

I think you were intended to get [email protected][['model1']] and [email protected][['model1.1']] (or equivalent [email protected]$model1, [email protected]$model1.1)

[[number]] retrieves the item by their position, [[obj_name]] retrieves the item by their name

It is interesting and I didn't aware this behavior. Apparently R will simply remove the decimal part and kept the integer in a non-integer number was provided when subsetting a vector/list For instance,

LETTERS[[1]]
LETTERS[[1.1]]
LETTERS[[1.6]]
LETTERS[[1.95156]]

all give the same result A


As a side note, the other function FixSeuratImage(seurat_obj) in the file is to remove extra images object when subsetting previously merged seurat object for Visium One issue I have for subsetted Visium seurat object is they keep the image objects in @images slot even if all cell from that sample is no longer in the subsetted object This function fix that by removing Image object in @images slot without coordinates

simoncmo avatar Jun 02 '23 16:06 simoncmo