SeuratObject/0000755000176200001440000000000014525765720012661 5ustar liggesusersSeuratObject/NAMESPACE0000644000176200001440000004076114524302405014072 0ustar liggesusers# Generated by roxygen2: do not edit by hand S3method("$",Assay) S3method("$",Assay5) S3method("$",FOV) S3method("$",JackStrawData) S3method("$",Seurat) S3method("$",SeuratCommand) S3method("$",StdAssay) S3method("$<-",Assay) S3method("$<-",Assay5) S3method("$<-",Seurat) S3method("$<-",StdAssay) S3method("DefaultAssay<-",Assay) S3method("DefaultAssay<-",Assay5) S3method("DefaultAssay<-",DimReduc) S3method("DefaultAssay<-",Graph) S3method("DefaultAssay<-",Seurat) S3method("DefaultAssay<-",SpatialImage) S3method("DefaultAssay<-",StdAssay) S3method("DefaultBoundary<-",FOV) S3method("DefaultFOV<-",Seurat) S3method("DefaultLayer<-",Assay5) S3method("DefaultLayer<-",StdAssay) S3method("Idents<-",Seurat) S3method("Index<-",Neighbor) S3method("JS<-",DimReduc) S3method("JS<-",JackStrawData) S3method("Key<-",Assay) S3method("Key<-",Assay5) S3method("Key<-",DimReduc) S3method("Key<-",KeyMixin) S3method("Key<-",SpatialImage) S3method("LayerData<-",Assay) S3method("LayerData<-",Assay5) S3method("LayerData<-",Seurat) S3method("LayerData<-",StdAssay) S3method("Loadings<-",DimReduc) S3method("Misc<-",Assay) S3method("Misc<-",Assay5) S3method("Misc<-",DimReduc) S3method("Misc<-",Seurat) S3method("Misc<-",StdAssay) S3method("Project<-",Seurat) S3method("Tool<-",Seurat) S3method("VariableFeatures<-",Assay) S3method("VariableFeatures<-",Assay5) S3method("VariableFeatures<-",Seurat) S3method("VariableFeatures<-",StdAssay) S3method("[",Assay) S3method("[",Assay5) S3method("[",DimReduc) S3method("[",FOV) S3method("[",Seurat) S3method("[",SeuratCommand) S3method("[",SpatialImage) S3method("[",StdAssay) S3method("[[",Assay) S3method("[[",Assay5) S3method("[[",DimReduc) S3method("[[",FOV) S3method("[[",Seurat) S3method("[[",StdAssay) S3method("dimnames<-",Assay) S3method("dimnames<-",Assay5) S3method("dimnames<-",Seurat) S3method("dimnames<-",StdAssay) S3method("levels<-",Seurat) S3method(.AssayClass,Assay5T) S3method(.AssayClass,StdAssay) S3method(.AssayClass,default) S3method(.CalcN,Assay) S3method(.CalcN,StdAssay) S3method(.CalcN,default) S3method(.ClassPkg,DelayedArray) S3method(.ClassPkg,R6) S3method(.ClassPkg,R6ClassGenerator) S3method(.ClassPkg,default) S3method(.CreateStdAssay,Matrix) S3method(.CreateStdAssay,default) S3method(.CreateStdAssay,list) S3method(.CreateStdAssay,matrix) S3method(.DiskLoad,"10xMatrixH5") S3method(.DiskLoad,AnnDataMatrixH5) S3method(.DiskLoad,DelayedMatrix) S3method(.DiskLoad,H5ADMatrix) S3method(.DiskLoad,HDF5Matrix) S3method(.DiskLoad,IterableMatrix) S3method(.DiskLoad,MatrixDir) S3method(.DiskLoad,MatrixH5) S3method(.DiskLoad,TileDBMatrix) S3method(.DiskLoad,default) S3method(.DollarNames,Assay) S3method(.DollarNames,Assay5) S3method(.DollarNames,FOV) S3method(.DollarNames,JackStrawData) S3method(.DollarNames,Seurat) S3method(.DollarNames,SeuratCommand) S3method(.DollarNames,StdAssay) S3method(.FilePath,DelayedMatrix) S3method(.FilePath,IterableMatrix) S3method(.FilePath,default) S3method(.MARGIN,Assay5T) S3method(.MARGIN,CsparseMatrix) S3method(.MARGIN,RsparseMatrix) S3method(.MARGIN,default) S3method(.MARGIN,spam) S3method(.SelectFeatures,StdAssay) S3method(.SelectFeatures,list) S3method(.SparseSlots,CsparseMatrix) S3method(.SparseSlots,RsparseMatrix) S3method(.SparseSlots,spam) S3method(AddMetaData,Assay) S3method(AddMetaData,Assay5) S3method(AddMetaData,Seurat) S3method(AddMetaData,StdAssay) S3method(Assays,Seurat) S3method(Boundaries,FOV) S3method(CastAssay,Assay5) S3method(CastAssay,Seurat) S3method(CastAssay,StdAssay) S3method(Cells,Assay5) S3method(Cells,Centroids) S3method(Cells,DimReduc) S3method(Cells,FOV) S3method(Cells,Graph) S3method(Cells,Neighbor) S3method(Cells,Segmentation) S3method(Cells,Seurat) S3method(Cells,SpatialImage) S3method(Cells,StdAssay) S3method(Cells,default) S3method(CheckMatrix,dMatrix) S3method(CheckMatrix,default) S3method(CheckMatrix,lMatrix) S3method(Command,Seurat) S3method(CreateCentroids,Centroids) S3method(CreateCentroids,default) S3method(CreateFOV,Centroids) S3method(CreateFOV,Segmentation) S3method(CreateFOV,data.frame) S3method(CreateFOV,list) S3method(CreateMolecules,"NULL") S3method(CreateMolecules,Molecules) S3method(CreateMolecules,data.frame) S3method(CreateSegmentation,Segmentation) S3method(CreateSegmentation,data.frame) S3method(CreateSeuratObject,Assay) S3method(CreateSeuratObject,Assay5) S3method(CreateSeuratObject,StdAssay) S3method(CreateSeuratObject,default) S3method(Crop,Centroids) S3method(Crop,FOV) S3method(Crop,Molecules) S3method(Crop,Segmentation) S3method(DefaultAssay,Assay) S3method(DefaultAssay,Assay5) S3method(DefaultAssay,DimReduc) S3method(DefaultAssay,Graph) S3method(DefaultAssay,Seurat) S3method(DefaultAssay,SeuratCommand) S3method(DefaultAssay,SpatialImage) S3method(DefaultAssay,StdAssay) S3method(DefaultBoundary,FOV) S3method(DefaultFOV,Seurat) S3method(DefaultLayer,Assay) S3method(DefaultLayer,Assay5) S3method(DefaultLayer,StdAssay) S3method(Distances,Neighbor) S3method(Embeddings,DimReduc) S3method(Embeddings,Seurat) S3method(Features,Assay) S3method(Features,Assay5) S3method(Features,DimReduc) S3method(Features,FOV) S3method(Features,Molecules) S3method(Features,Seurat) S3method(Features,StdAssay) S3method(FetchData,Assay) S3method(FetchData,Assay5) S3method(FetchData,DimReduc) S3method(FetchData,FOV) S3method(FetchData,Molecules) S3method(FetchData,Seurat) S3method(FetchData,StdAssay) S3method(GetAssayData,Assay) S3method(GetAssayData,Seurat) S3method(GetAssayData,StdAssay) S3method(GetImage,Seurat) S3method(GetImage,SpatialImage) S3method(GetTissueCoordinates,Centroids) S3method(GetTissueCoordinates,FOV) S3method(GetTissueCoordinates,Molecules) S3method(GetTissueCoordinates,Segmentation) S3method(GetTissueCoordinates,Seurat) S3method(GetTissueCoordinates,SpatialImage) S3method(HVFInfo,Assay) S3method(HVFInfo,Assay5) S3method(HVFInfo,Seurat) S3method(HVFInfo,StdAssay) S3method(Idents,Seurat) S3method(Index,Neighbor) S3method(Indices,Neighbor) S3method(IsGlobal,DimReduc) S3method(IsGlobal,SpatialImage) S3method(IsGlobal,default) S3method(IsMatrixEmpty,default) S3method(JS,DimReduc) S3method(JS,JackStrawData) S3method(JoinLayers,Assay5) S3method(JoinLayers,Seurat) S3method(JoinLayers,StdAssay) S3method(Key,"NULL") S3method(Key,Assay) S3method(Key,Assay5) S3method(Key,DimReduc) S3method(Key,KeyMixin) S3method(Key,Seurat) S3method(Key,SpatialImage) S3method(Key,character) S3method(Keys,FOV) S3method(Keys,Seurat) S3method(LayerData,Assay) S3method(LayerData,Assay5) S3method(LayerData,Seurat) S3method(LayerData,StdAssay) S3method(Layers,Assay) S3method(Layers,Assay5) S3method(Layers,Seurat) S3method(Layers,StdAssay) S3method(Loadings,DimReduc) S3method(Loadings,Seurat) S3method(MatchCells,"NULL") S3method(MatchCells,character) S3method(MatchCells,numeric) S3method(Misc,Assay) S3method(Misc,Assay5) S3method(Misc,DimReduc) S3method(Misc,Seurat) S3method(Misc,StdAssay) S3method(Molecules,FOV) S3method(Project,Seurat) S3method(Radius,Centroids) S3method(Radius,SpatialImage) S3method(RenameCells,Assay) S3method(RenameCells,Assay5) S3method(RenameCells,Centroids) S3method(RenameCells,DimReduc) S3method(RenameCells,FOV) S3method(RenameCells,Neighbor) S3method(RenameCells,Segmentation) S3method(RenameCells,Seurat) S3method(RenameCells,SpatialImage) S3method(RenameCells,StdAssay) S3method(RenameIdents,Seurat) S3method(ReorderIdent,Seurat) S3method(S4ToList,default) S3method(S4ToList,list) S3method(SVFInfo,Assay) S3method(SVFInfo,Seurat) S3method(SetAssayData,Assay) S3method(SetAssayData,Seurat) S3method(SetAssayData,StdAssay) S3method(SetIdent,Seurat) S3method(Simplify,Molecules) S3method(Simplify,Spatial) S3method(SpatiallyVariableFeatures,Assay) S3method(SpatiallyVariableFeatures,Seurat) S3method(StashIdent,Seurat) S3method(Stdev,DimReduc) S3method(Stdev,Seurat) S3method(StitchMatrix,IterableMatrix) S3method(StitchMatrix,default) S3method(StitchMatrix,dgCMatrix) S3method(StitchMatrix,matrix) S3method(Theta,Centroids) S3method(Tool,Seurat) S3method(VariableFeatures,Assay) S3method(VariableFeatures,Assay5) S3method(VariableFeatures,Seurat) S3method(VariableFeatures,StdAssay) S3method(Version,Seurat) S3method(WhichCells,Assay) S3method(WhichCells,Assay5) S3method(WhichCells,Seurat) S3method(WhichCells,StdAssay) S3method(aggregate,FOV) S3method(aggregate,Molecules) S3method(as.Centroids,Segmentation) S3method(as.Graph,Matrix) S3method(as.Graph,Neighbor) S3method(as.Graph,matrix) S3method(as.Neighbor,Graph) S3method(as.Segmentation,Centroids) S3method(as.list,SeuratCommand) S3method(as.logical,JackStrawData) S3method(as.matrix,LogMap) S3method(as.sparse,Matrix) S3method(as.sparse,data.frame) S3method(as.sparse,matrix) S3method(as.sparse,ngCMatrix) S3method(dim,Assay) S3method(dim,Assay5) S3method(dim,DimReduc) S3method(dim,FOV) S3method(dim,Neighbor) S3method(dim,Seurat) S3method(dim,SpatialImage) S3method(dim,StdAssay) S3method(dimnames,Assay) S3method(dimnames,Assay5) S3method(dimnames,DimReduc) S3method(dimnames,Seurat) S3method(dimnames,StdAssay) S3method(droplevels,LogMap) S3method(droplevels,Seurat) S3method(head,Assay) S3method(head,Assay5) S3method(head,Seurat) S3method(head,StdAssay) S3method(intersect,LogMap) S3method(is.finite,Centroids) S3method(is.infinite,Centroids) S3method(labels,LogMap) S3method(length,Centroids) S3method(length,DimReduc) S3method(length,FOV) S3method(lengths,Centroids) S3method(lengths,Segmentation) S3method(levels,Seurat) S3method(merge,Assay) S3method(merge,Assay5) S3method(merge,DimReduc) S3method(merge,Seurat) S3method(merge,StdAssay) S3method(names,DimReduc) S3method(names,FOV) S3method(names,Seurat) S3method(print,DimReduc) S3method(split,Assay) S3method(split,Assay5) S3method(split,Seurat) S3method(split,StdAssay) S3method(subset,Assay) S3method(subset,Assay5) S3method(subset,Centroids) S3method(subset,DimReduc) S3method(subset,FOV) S3method(subset,Molecules) S3method(subset,Segmentation) S3method(subset,Seurat) S3method(subset,SpatialImage) S3method(subset,StdAssay) S3method(tail,Assay) S3method(tail,Assay5) S3method(tail,Seurat) S3method(tail,StdAssay) S3method(upgrade,seurat) export("%!NA%") export("%!na%") export("%NA%") export("%iff%") export("%na%") export("%||%") export("DefaultAssay<-") export("DefaultBoundary<-") export("DefaultFOV<-") export("DefaultLayer<-") export("Idents<-") export("Index<-") export("JS<-") export("Key<-") export("LayerData<-") export("Loadings<-") export("Misc<-") export("Project<-") export("Tool<-") export("VariableFeatures<-") export(.AssayClass) export(.BPMatrixMode) export(.CalcN) export(.CheckFmargin) export(.ClassPkg) export(.Collections) export(.Contains) export(.CreateStdAssay) export(.DefaultFOV) export(.Deprecate) export(.DiskLoad) export(.FileMove) export(.FilePath) export(.FilterObjects) export(.FindObject) export(.GetMethod) export(.IsFutureSeurat) export(.KeyPattern) export(.MARGIN) export(.PropagateList) export(.RandomKey) export(.SelectFeatures) export(.SparseSlots) export(.Subobjects) export(AddMetaData) export(Assays) export(AttachDeps) export(Boundaries) export(CastAssay) export(Cells) export(CellsByIdentities) export(CheckDots) export(CheckFeaturesNames) export(CheckGC) export(CheckLayersName) export(CheckMatrix) export(ClassKey) export(Command) export(CreateAssay5Object) export(CreateAssayObject) export(CreateCentroids) export(CreateDimReducObject) export(CreateFOV) export(CreateMolecules) export(CreateSegmentation) export(CreateSeuratObject) export(Crop) export(DefaultAssay) export(DefaultBoundary) export(DefaultDimReduc) export(DefaultFOV) export(DefaultLayer) export(Degrees) export(Distances) export(Embeddings) export(EmptyDF) export(ExtractField) export(Features) export(FetchData) export(FilterObjects) export(GetAssayData) export(GetImage) export(GetTissueCoordinates) export(Graphs) export(HVFInfo) export(Idents) export(Images) export(Index) export(Indices) export(IsGlobal) export(IsMatrixEmpty) export(IsNamedList) export(IsS4List) export(IsSparse) export(JS) export(JoinLayers) export(Key) export(Keys) export(LayerData) export(Layers) export(ListToS4) export(LoadSeuratRds) export(Loadings) export(LogMap) export(LogSeuratCommand) export(MatchCells) export(Misc) export(Molecules) export(Neighbors) export(Overlay) export(PackageCheck) export(PolyVtx) export(Project) export(Radians) export(Radius) export(RandomName) export(Reductions) export(RegisterSparseMatrix) export(RenameAssays) export(RenameCells) export(RenameIdents) export(ReorderIdent) export(RowMergeSparseMatrices) export(S4ToList) export(SVFInfo) export(SaveSeuratRds) export(SetAssayData) export(SetIdent) export(Simplify) export(SparseEmptyMatrix) export(SpatiallyVariableFeatures) export(StashIdent) export(Stdev) export(StitchMatrix) export(Theta) export(Tool) export(UpdateSeuratObject) export(UpdateSlots) export(VariableFeatures) export(Version) export(WhichCells) export(as.Centroids) export(as.Graph) export(as.Neighbor) export(as.Segmentation) export(as.Seurat) export(as.sparse) export(handlers) export(intersect) export(plan) export(with_progress) exportClasses(Assay) exportClasses(Assay5) exportClasses(DimReduc) exportClasses(FOV) exportClasses(Graph) exportClasses(JackStrawData) exportClasses(KeyMixin) exportClasses(LogMap) exportClasses(Neighbor) exportClasses(Seurat) exportClasses(SeuratCommand) exportClasses(SpatialImage) exportClasses(StdAssay) exportMethods("[[") exportMethods("[[<-") exportMethods(Overlay) exportMethods(colMeans) exportMethods(colSums) exportMethods(rowMeans) exportMethods(rowSums) exportMethods(show) importClassesFrom(Matrix,CsparseMatrix) importClassesFrom(Matrix,Matrix) importClassesFrom(Matrix,RsparseMatrix) importClassesFrom(Matrix,compMatrix) importClassesFrom(Matrix,dMatrix) importClassesFrom(Matrix,dgCMatrix) importClassesFrom(Matrix,dsparseMatrix) importClassesFrom(Matrix,generalMatrix) importClassesFrom(Matrix,sparseMatrix) importClassesFrom(sp,CRS) importClassesFrom(sp,Spatial) importClassesFrom(sp,SpatialPoints) importClassesFrom(sp,SpatialPolygons) importClassesFrom(spam,spam) importFrom(Matrix,Matrix) importFrom(Matrix,colMeans) importFrom(Matrix,colSums) importFrom(Matrix,nnzero) importFrom(Matrix,rowMeans) importFrom(Matrix,rowSums) importFrom(Matrix,t) importFrom(Rcpp,evalCpp) importFrom(future,plan) importFrom(future.apply,future_lapply) importFrom(future.apply,future_mapply) importFrom(generics,intersect) importFrom(grDevices,as.raster) importFrom(grid,nullGrob) importFrom(lifecycle,deprecate_soft) importFrom(lifecycle,deprecate_stop) importFrom(lifecycle,deprecate_warn) importFrom(lifecycle,deprecated) importFrom(lifecycle,is_present) importFrom(methods,"slot<-") importFrom(methods,.hasSlot) importFrom(methods,as) importFrom(methods,callNextMethod) importFrom(methods,getClass) importFrom(methods,getClassDef) importFrom(methods,getClasses) importFrom(methods,initialize) importFrom(methods,is) importFrom(methods,isClass) importFrom(methods,isClassUnion) importFrom(methods,isGeneric) importFrom(methods,isXS3Class) importFrom(methods,new) importFrom(methods,selectMethod) importFrom(methods,setAs) importFrom(methods,setClass) importFrom(methods,setClassUnion) importFrom(methods,setGeneric) importFrom(methods,setMethod) importFrom(methods,setOldClass) importFrom(methods,setValidity) importFrom(methods,show) importFrom(methods,slot) importFrom(methods,slotNames) importFrom(methods,validObject) importFrom(progressr,handlers) importFrom(progressr,progressor) importFrom(progressr,with_progress) importFrom(rlang,"%||%") importFrom(rlang,abort) importFrom(rlang,arg_match) importFrom(rlang,arg_match0) importFrom(rlang,caller_env) importFrom(rlang,check_installed) importFrom(rlang,enquo) importFrom(rlang,eval_tidy) importFrom(rlang,have_name) importFrom(rlang,inform) importFrom(rlang,is_bare_character) importFrom(rlang,is_bare_integerish) importFrom(rlang,is_bare_list) importFrom(rlang,is_bare_numeric) importFrom(rlang,is_missing) importFrom(rlang,is_na) importFrom(rlang,is_named) importFrom(rlang,is_null) importFrom(rlang,is_quosure) importFrom(rlang,is_scalar_character) importFrom(rlang,missing_arg) importFrom(rlang,ns_env_name) importFrom(rlang,quo_get_env) importFrom(rlang,quo_get_expr) importFrom(rlang,warn) importFrom(sp,Polygon) importFrom(sp,Polygons) importFrom(sp,SpatialPoints) importFrom(sp,SpatialPolygons) importFrom(sp,bbox) importFrom(sp,coordinates) importFrom(sp,over) importFrom(spam,t) importFrom(stats,aggregate) importFrom(stats,median) importFrom(stats,na.omit) importFrom(stats,setNames) importFrom(tools,file_path_sans_ext) importFrom(utils,.DollarNames) importFrom(utils,adist) importFrom(utils,argsAnywhere) importFrom(utils,getS3method) importFrom(utils,head) importFrom(utils,isS3method) importFrom(utils,isS3stdGeneric) importFrom(utils,methods) importFrom(utils,modifyList) importFrom(utils,packageVersion) importFrom(utils,tail) importFrom(utils,upgrade) useDynLib(SeuratObject) SeuratObject/LICENSE0000644000176200001440000000006214473173564013665 0ustar liggesusersYEAR: 2021 COPYRIGHT HOLDER: SeuratObject authors SeuratObject/data/0000755000176200001440000000000014513704651013563 5ustar liggesusersSeuratObject/data/pbmc_small.rda0000644000176200001440000016720014473173564016402 0ustar liggesusersBZh91AY&SYN؝ H@h}x=zF5Xj:j[j[`/lR(P)^՛RjEJͥݺͰ;]vaJVi2iT])&(hBB (j{b=۞j׹`Ow 66 s9HP\/Ñ(k %-Sz{ Qn `!ljD5,_wDٸTݍԬVi+튪JT U'fʛ[k:$'}SRcIQrmMb٫L kb6ĩvٍ$[3 KRHi\oqLZVՙU͊(B-dPb@D@144 4<FCM4M4&2hɦ!4aCMFH &2i&FL&h!bi 4A y@L@CL6=izLSS=Qe66jijzbM16ֻLJ\%ʋ0h;5CG"EC`Wַ/V)E ^9d:ȪE [=ـǽ ?.n,9C%k1v)  ʡ(Jv4UQ[LVdĈ Y߶~N[֢3AFZ59te/d ֵAiȡ#XRh2dk[Jq 3V5RcPNA,1aSOZ$b~֍hiO e5'o(>ۈiNcz>NO*'Io.A%_C'#{'!*& x15j lu!f2x8[f\&W9M'%\08FmG6 I᫞j^)8ky*Sh2L*!y'Zi;9m SDhbaPF aPLN/d_]D금4BY9_s%lBR5՜^QHEqlNXA-@ xf:W64fF8$ٺ |2BزuAbARVƔ%fgaiy̖m`|y{SmH )vNn֎ i譺EuN! A{qftqc(7KCy|-9m'6 /IO{<ܝ2TQZT;\g'(szG4<mjg"6[31S_d9Cm(m-GQGhbǞ҄\?QIA랠#mr_-9}[9l{>>pI{Ecy=,I*'I1$L}F[`@u!D?usXĸEܐ@1֖DDƘM+dSTϚjizc^ngU&9B2L^$bb " x)KX*ŨeE<ߙN]"RФbdqb/ɮkl|4*Lq1e+ Neh+D:-TU*'L;XI=ڂ,F}lDlQQLTΓ$.6z]tGz6rvuritixdCb#ʫOq٨% AA^s5P\n@?ǡު=g̟]X$>~}GS P')! vP%id;z{L^ԑ>G<9;o>ۡ7AqŃg=8cЄ{.7iÿؾWuwӿ۟j>(GyƣD#Nzյ-H}gFitwGy[|8uڥy\͜6wNh,+l}{;?B:*:ˣ4XGՊ**cGW,MwgoM}~gֈ}O._V>7l+Wbں;p厞z\N$~!]L}mFM[+#v1=WG?i",{ǃ~`ܝU{ 4={q!ر\>r$1ZWs$ݕdmZ:;N\>sZ[jG1^x\4|$w1:1&޷6:>WWλ>G#;;z\z޾i"8ꭼcV+RHң*xNNy4qFbbƘx:p۷$6m&4mi\<ʻ~E"e"V'ryerҩZuai?#D:/U\*cN1JmE椑[|K vd4JVi&+h<򰕵V+« ;1R@`Q]ib4יHT:,+&UE*WFUbLcOl~T†,HadUm1xNuW*cou¶a^w-G?P!URG{O{)MTw=>rO}XVDGECDÿjAZDɦ?>8CX꾓IUx:p{ZrZyC§^,r8WsLp¸i^-FlLW-UT!8B(>)H9",`v) *lsj4{u#O}Swlϴ妘cmw9pGş쮌yԦlr٧nE}J1էr|vm>(uV,69a}**tiRǝ%y>ētTUUU**w?IJUT]N8pGr!ET*W{\ex4+1JT &*۫h\4Ǚ IʱX Ъ~?UU+l+gɥ*QF;U*laViSMOI1b9w8i[~xrۣp0 S|opT,V:*p)1RZbpۇI,1J[a*ɥ+J4*f Rp'W{8QUU hҕ*SҸJ)_N<..W.z\t|'syݏCDb}zb˜$=ScUUI^* pJG!ڪ˜)Tsq4ڎUcl?Dm )ʱշlLW*=)UULyUɧXƘ6ᦜ4:z[U6V6x6Պ=>1誝Jwmlxғ tWͫj ?iM?iNXmaV&8V9}mR4óOכTUM1 4V#g$RQ0W1ZiʧON=v8iyU&%y?NNIMŦpx?HNXҕTSaU1Uac+ƌT9V6ió:*ѥ~)EU)UOU1~ 1Nl8+ʦ)ƚM41Xژ+txiurM*ITaU:g"b FRiN0SbmucO*JJQ_UcF1Zc_+j&iZmQlmcO9h]o+GZaS" LF)UR1m4a1U1X?fppM6'{LUrW{m۳:9}#jSNWslrls TNZ{QC$+ha$h߀b8~`{OG QZTc]ZrpmN=ma+x+Ji|VX|Wٵw9{/vrѷ{ҝ*i^u1JcUՌ~w4-^7tdmfA4N]N\9*-<3 ̥`*@qs_9}(u_04S$X.tTAP="c='|EhkrK4S @nd{hS 3i$dpC0 `5hQ ܆r>'4,KO. IхU_{<_u8{fCc<!d^;$''# p  q.ҔGbgL zD !?rbE1@T (|{9՚HB )KAE2Х$lh*688NFiw𧧭J"2O-B>@!D85PLTE1SRDLO wJ>tOzq֓wr0 !a,45 njXi !ad,2 aaajB!j 5 C!P,,)'otؾUrյ˝" ( TEHRRaO tp[ JM(DSHyXL"v =L`TI@*žJB(m.pF'T[6@(< wd"$9BQIPRP "<\T} $q` 0 Geg߈'4!HgHL@"X@_|_@}r?@5)L@ ِ4*lH<t0(U+:yᬆ"w_M.{L&R$2fdJ?ZnVxD ~?Ċ?RrntsG`7̤[Py:[r&w(_)yyAS4*3&|u_ğDFa6.JKۜZ;f-b5L gZE |b3ۏ'X, 5?ըES},Wެ;̋2}X 8+ܦ4ONcrj!@`cP g'UvޣG#>| uZD79wO(dbtf:m H kjLT4Fى5-QF¦"ۆkl bR[F&5RAUQAEK0Qݻki6SA5Ii5 TB@8p 5WV5h}\DWJ#^@(Fq|q8>On'>i vSx0C[I \DRm@iьZ3Sk`2u@VU@D K"=\u(Nk>U@a'R 6WTRc !=Ge$IZ-\sy(#v4(Iv_S~Gk tʹKA_:P鲍XWG! JILCݻBj& C {|P0Zet3c[ɦE.mTǩ@K ^G0΋z\ DWbMl@ =-1Rd .J!dO6NC*EiC,||(jBK[mg#7',$#PCR1z |K4bM.s.<{]-{LWU{-P'.omT7`SXv`B}NjL5?>v'm?H{Iσk25ܐ"KɒhlIrWIB{ArowtNh sCV'k\yJry3J|C"$ });~R`}s{ZD~׼LgcccP]jrP u ZW ^7s'@Ck~C <|{* z:)*(ƭ[T0?Ԃx yymHQ<(d@oLu1ɦ Gu lG)8fU ?E#Zj  9ޑ^;y~ R儒mԏ0Xk7l=M1{*8nk2ҋCSPmB: !#¤rQ(OߺGhHH{>o|1^7Kƺd¾_K}[wbTDDyZ*;~.aNµ⌣yi<MAjD&ٕ_qPAHO2"$&usl<A8a8m|/ )g箇Xz|>]yJ-۬W.+/ Psk1r֎veK͒xb[*ʦ(QDvdR@!"G8{ēEF[H.TZ>[zk7C5{ GH }XA5DC1l^VJ 2rskT~ZY\i= $%ȰBYg7 l>r2Q6TYk+y>>1|H{id;8*Xj IWK\,@7n,|E&-f=`=}: @+zo\}v׿enf}FVXG&H_bQE KT9K]CVusVzWe6YʠӢ(@71POE gȣ`_9Ϲ>I#)Cst'[:Jؠ A}=kgwtsr(([Zg\Ө6H@*|fC{[i橒?Mk]m~s࿑\ry$r%?, I3L\aH$2_*>=/ݛdk0k;UA<:;T-P}9+3اH2x{p>JƊ-̽,~= A(x_g?/c~ͭGa!QPG Ϟ PMζG%։K4]z ܵ/Ϸj$$դ't³=M8 ^9mVc=OH bH;S:-@5I=屗֣PAnHO!ieQc Z&C‘ :K'k*!?2%A0<dz;0)%@wߞHFAs6{oiڙ6Dh{8~}HoC o O^?gw;ݫ+FvG+@(| B?hf(>tp|T?1r>;KƮp͎`*~Su^RЀ~3 I^`7+v)c *c.^Ǻ& bd22:r~pK_7@1քo!x~%Yj4`_w pxU[$ݐ"L4KG7W*-Aq ^PqRZOG,$pw[(A ,>$hk\ aa= r^!! !T#=E=J,mP@?((|Dg|\D߮롯L06yjDo=u!@7LI> 7,,؇Ĝ@g6IvA ' 7"S+]0|6n%F+Y-g%ۇdla7!P (a-O5tdhvd{DgqoC$TBal3!0络)?ِ: *Pޡ|@{NPH6iheш\uaj(S&ߓnr}fIx߇]|j)aGE|] 9"QM@$G  -`SH,/.Ned(ఈgfr9ǣ;I-DwPa m:e$L0X(|=?ԏ: (Å˙eۥ(Yӆ( ?nl@D3hH$7Wp<$hfv% ﻤV\m˔ܧ#x`G_Z΋6inIv bZ:z1q $9')u-oyHu*#x䭚7%@G8Xʀ Ë^jb ^a5!w=4阃yzyT뺫Sfy֙x޴=P;>'$aZ#@)S@"Go t0M^Huz [5'j~m|(yO^ >Tl ҫV&]38Ty\t7g̀D hL||o)k{—eܮT D~ObxxU[do$:xV&.P\xH)LnKDI5˦k^O*0$nfog/'K,_ WXѱE]?*TOFdPk3^w@ h2 p8`9`xotN,YHb'sgSuԩ}F0_"p~LuUsa&4<@|6lΗ5z%+"DPaH$c\WwxWI=!T5(4Sr TA%2pcd{5Ϙ+; JJ=2+_>^w3 $^pZUwn'6DŝaƷJ@Gݾ$ >@5 v*(l`"INU1QKߟYw۳Mlo/⹴ZoIBCθNeIxմ@ 0oxNo=v+a`X{">q{߫aj{o_lćHz@${Rdkp19Bq.,VXUBF^oLdu; y?%):>`l-%'Qჳf@L(LGژ<#v`M8/@0i-S Eaw&!F~7߾Ssi DȲTLi:Z{?#ra?MM= OנO_$PI$n: ms1J OʀlzE6<\VAk;`3FȑܧgnX(R7ny5֯+h4C}gAP.TFXdZΏZ[r.|2;k;/…} AI;G`s2uW`Ibx_ ;&:M Oib3ƻ_:jѭ^0*0'=n6V@Oˮh8J.@NP<ǝ:Y]9]uU۟UUAȷnd6w*t$|kAzDeMV;-J?>꽔w6m-?'8[]UhUe΅T[v {}7ewFy?x>#?뇹>Gr5n9:^?A "5Wlujjc~@ XvNl5I&>,5DC@ NY wÙf/Inc')(MJAJE$2'k>{4dYp+%Gݛ:"zr!lCtf{e9?Ik//MI% BnZyxm2H`f'i#"Z)bZ -W/Q!J#*HɅ!5DNr!ru70ǧh|5WZ1L;zdKgorN5Zq,`Y-Bǿ[r@F+RA  !ȁ0c@=HTR&ܥ({o&LHI$W?#^.ε{P=7kWf=mR3'Z_@l[$ywPbDS@d"2ϛDW5X );DO'3!c52/V6n#Jn k߀GGmY1=EPJVH D%MD4QHf:@?Ĥp6/ v H$ ےVA}>/Q܎F@DT?Q~~Ԩr"zl Ùk.9t¬Rxy{> >Ǩ|-+|ʮ3A+on9R 45L)ay7+Aw֣2 uR_+Q xIzB{1y~Z.x=(on2 (6xwxٛu-snM+3Aƕ5cE&kFd4DsDik-uC=iZvg3{szܽ1g +ki x,-Š,kh6aۙ30WҨgVj8NNwְ¯BYPZ9&Fn)yN\`[7Kdo@oHϱHǃi @g7nK nI shdf|~I8M2@=7;33Xr 3hY4]GYryɇdAE`6a*JE#>E$}Ss]?WzmЗck4_~s].[h! ﺌML=b)q_ߕҹeTT>1#rB/ V2FGC{/!}$"urq2fgVeIAC7tL[\E,؞-L[Lϱ >=i.Dpl;!Z\i%MR~J4'I ̌/y]1jeܨkzé2/gXOv+P*xb^0~ qȱ>eN]] rUu}\wK k:Wv*9@y5c/3x,qɗdh?'iot^rLR">8־bZ$&| 2h&,ϿyON$^o#LÇɔ fute~H.I~Sɡk;ےkq0}lm0Y]}m D!)(#DTIeLq.=~24}vSpQ`*v=by0߱ucWo`T\9v\V1J1JU\x ZpoKx]c[k`|'}f ܛ9F?!miVI""}Ky|: YL{f.UJi0}5L,lu1Pߋ6Ixm0Gņtp $G!KBA0j+N]?J8z(\ Dux ~Fה%bA`Z\kq jjܳ$I'3ݛ08'(Z9^)[:y95T\1D^gU}E<Q^T)DPmGAApR0rg; {mBO(f-;)zk|1{DkT5/M[Δ=NGn1rys7¼PmD _[Rμlx۞2r_vgʉsbU*4I)m]n=lvs' Y>:-s @3HW[ gy+׭E<_=-2 epR|ר> \3@r;dϠ~gOpy2#5M60ҝ`jϑfsБ$U)J|䫮ּJx{>]8Q#ZS!ȷ@=uFM5IIa.&l7G딦MHX5*'HeѲSBh*m+ݨ]O`A#q }lnt[?vX Ba3ʛRu[݀@ v??zt\ǿW?x̡2u4[.fۿR$brDzWar[ nɑaFF |K^ӭ BlW\ҡC:ek VA|[tA5}k/MƎc @\ 1<0Z3 M(}.̉\9HF"kV[9ZTOˊ0,4VG;Ww> A}rHYrtQ3*f[@d@ӏrۥ{'L~ MوFwor_>>O,[7uD+.߆X[*\@Oy6| 敺V .\]BB'" ' 5-<"\+cpZ~\q8[ 7A,B [z׽Vam|&&ڿudةڧL9wGvIɇ E׻dw<@֭ T1=9L|Voy]=nOͣ{aR*ȀVpXvum|wPr9|oWl:d%,|VC5>w=0O J^}-ߡZ1X[]5T 74{%1{ڟ5vzYjujK-fPܿTSBvZXWe ?&!79W1PN~DOe]k:~wA7Wd:He8oy^jm+KE-gWT5EKTtMXho>oF;ۅ/\+X̐2%I31'aljTmp݁R)RR*fY-=k]TfT(Ҙ`69CO\de#2B?6w[zZ/.گ`{k]Χ=iyFy_o_gwI.c _?Sag=wAS̈́pfٝc q J4 [*z15~LEw gG?5]C~S^`PJDk\سdD6k6h\\NFT0C; ǀkNV,,'qOY<bXniN@Z8bsgPGlwYj9c,mM 7Ke$k b<;+>uut2q7 =hB"x0y$!ȁp]K!Pd( Ynj2C3"rTV8ҬZNB;ouTN{Sk5dd[ ç&Ttk7;?3M3sl;Ӧ8Iծ"Yóځd@(UEDZ!5X[;pS#pLSqΤHF~d;q0;I[^ba7cnnADoa["(䯍J ]R*^ͪY^y`f{=îvaE{d€gBD'a*j5 DL[sV&㳊&0ț ]|! [IֳdINzq->z)eKnvͫ)t -PX{fRmLMm蛈-Ʌ"j8Q".Ya^'ȿ. aͯ$ī9&+Љ.be!SXԜ6f_+K-5禖0&^2a"x:+IհlF#5y34](2Q!J:! #/fyW*xԼ̽4Gf?N2l%x4|Uy纺`;)IgTaiag*d@Z+RsS kVe!Da1}trvjyrQ# 锅C:N/д \* 8QO"#\39"0O")f\€rNO{ŲNY=5<ʾbM{~{>t/ySo~/1㾧 Sd|E[zCk;ъQ' W{7H]! Ei Ql: BY ٮ Z4|Ĕ2)#kw,26y0_\`UjH0]ˤAywPBwzd1PSZD Nt# bX~W7;<jn<_o Ք*]]3f[)*4c}P'5. j].b`T&8&PɦLiil-NS哋0ժ8yX2 6` tg)CamZҮ.#1ZY/Ddls.Icgye$VK^LFɳeaggK"VC02d;ou ,Mc[Z-k$xŶ-fH֐5 z>D X$JKVQM,B/vJ>lg*~/[}mc-3p:>W (:?^ 0\m\e\|3v89EO&2Y̥ ^ " jH A3WS&4S|((",YfTB!:׫'A1ٻI,\z<=;`d-ִjQ_%V1h[ԌˈUsj؜ ]jCEze|V@,NUα]`<;D5e#q_koc=y,ye^*yjl)^~0XT@VxuwrE[7# N]HźJ [+UU]nj< Bu8La .h \e@L`#EY \a=@C*wI L46vm0n5:~9-% -kM4Xg(RYS\@,*q2E@NVr ɝA gQ~MxU=]uWSFf?ja%=Ցn-{DG<cb'qlϙ,3lRh| `eaVj1/6 28  ̪{&d볹L^BB ,[Ch"q&/VS22 %ژݐՉk NNOysG9Wq:h5rD 4)Eqֆ/#j㨰[N 1^F;b5?;v'.u4N%ya n9 lVbJ ̈́b\Mbm"<`53 SuhgFu .ٌ qFvX$gI!aK8(MCTVfW%b.ј C8MZlEYtBEݱ /frףe=[~.>1\ ĵom>,= MPMɾ>x-]jÎd[_X0>+*)MnkM5Z5y]{&gvBB 1(a۪, D6mi՛t(.hs#&,pkk A}u(p!:Ԥ?w-߯~ߨ{| fޣb""+1x .l{)bptDD Hs0KhՂP^Xk.ET?*,8Xg2yOO6T4NatD63,\dё|92P0 t.qB'DYFr3qo.tbPcۧ_zkWtǧ]ףG]Et(n9hM3ku !ܗ~8ہd=ZonY'r#p,k[2[)fPZEIDKK"Ni0DqVZesc>eUI51U,[fߐ#|A=7.Fq-ǷX*j!#7ry*1'3,]< AA`F9SB5Yf 3аeUK#f:F,Y0@ WHd],3Ӹ2kʖ N/2&3 A3\X<;LR[)5ђ=@RQ 5=WqoPiZCx}d%]]?~~-7W}RzV:9fgz꺞!TUS&T#2ŕ bn + 8]vt^6DS$ŪWPE+C ]X9qh`Hw (̌HrCߑg&D*ik}l&y2, bór'z uR:;/f5e-]M"$hkh.B,^lHUD`Zj*:a+0_" 61g}S>7|W_ퟥ5>"mS@Jm7SN)vU@xu=~.V2 Tq!,3ш/l&p qlXQcJ9a]ܒAF`kMճs=n~;mk'DoH%WCoHf q~y|/Mo7-3;tM_˿}7硷@D1n\yW&l.D<783Ȅv >ˋYqs7 ~a:XjJR()i !(iZ(HBR((( B&(hJ (bZh (h(*:ƕ*Bj )()Bh (+FA5AE$IAOhiuITUPA@-Q 4AJR @U%4ACIPKPRTR@ AIML!^ J(*d"("((J(5d44 SEJA LBPQҔ#Q44dCES@STdCUE APf`PEE9NCdQQ4Ҵ4aME4M!IIH=G&+6 WM+Vt_)>CKm>uKvܣw4r)3hPfQW ZJ>zw>46vUυĨŌ?Vu&28??GvEU`7Cn;ވV٘KNS.0&MjiWRٷie:4Vt? .Fiimul%&` %aecϗN/ V65IOw+#5cm߰"u_\F'K?wEa乴sɺ8ɹM?t8ÓJTU^0ޤ*|hoB7PU PDc7y_WZӟIknz8X\"!(~#sٱz5{ ZIBhJ)*e(hi )J*!F3H bJ)( ZJ` *Xf (j`(j"%&b(h (h*BH!4 =7|K2SfWzqu*KYYnلG}3:%QIrb ^=W)PH1fݜ} (O⹺{ 8' 8(KĘ4&AH(ȺԬRRXMkB4پrSE^i?X0 8ߔJf@ rl}tQ~y/$.["=o߽;޸HP  ݻ+z:6Cw5nI PH׈?n܃3;lj>|sޑ`f]MF->ۏΞ~\!Ax9%$@č MPT9 HD4$Td AAKJM1$M4҅DYR4Y9{Nh=Tp|:ޏuJd9ĸ2nO3YYV ^CR~T#]eo;\y4^:Ky. c9tc ϷWq'_Gè __=?`Oo|nsmsC}ZߨyA/O|;zަ=0vR]ngFs'wො! n_U:E}7XGۘ>cɳd|=}_I5m;﬎zv_mrTa~qfZ2v2OoIz ?B`]{j `~,Ř;~H~n{r]0:_Q_uA:A^><= ա4u mM1`scOW@T]GQk,]|SEk?Fۙ_gcl3m{yfuyOUדּߗxgߙV9|\7Ia،,0Ѷ{_YDD"m59>^K?Iu5r Q31[Os2#9t`y9#uw}4$tׁ~ٞҸ_>A.`fFz쳖 #b1P` {+iǙ/!FYh}V,=aeCVU!-+*64*>|@F B٦4jĒͨ`BkBd>9ky򞏙h?kqh0ɫʊJ+X)j )())(hc3./2G,o.zo!f1t6$pߚc<3 ٓ!Ҩ(RD#MՖ-ɢGo?'??q{fBAj̱#;#S)`aDw NjF5tvySݯqCV:"6櫭kz[]}|P<z,I'_qyN$E9=M̷;^:y/ښ++PU676Y~{YF7K^>9ӀT~g{nӱw~[~eO-[f@~xNCk߶'_ ؼ[]oo좁nL 3a QF=~K^g-IiJ&$Avߧ^'YSjocMz?~t~_kΧ.!.83{l"+Tr?ߩUsQ,ぁDci8qX1PL5Z,Vy lV^c*s'4`uBM=7 P5,~PfFN/TB%/vGc@tCZdϛ$d3='MW2_d+o#xvKq;xyxQ>?3QR4LPAT DI1v !Tfv0cIuXƒu\TG K``kuN bU#< u }r`̾]adO&)E1!@qvZVmfRise[ۮ<,Axb,q7'b5S ]iV|O*qUc8Qݨŵ8^NB69m׏燮3'Lh -ffJʃB@~@TfhIk Cw}-hRl.Fi9ՙ.c')laɝF %C wYp rѮj-eMʁN(.N?hw6ọ 7 -*3)_,lٰ \o&~bݿc30\zy+HUG;my;Ғ&[Eh̀)i)(ZB&hhoVQ}]w&Jiei\a EEoS]|M_ލн-e's0Jho-O䵘LM±/_0Fc ݛ"_b1<|W`Y6K΋\[0XaffOP9c;Y'4^%㴐qY.2\N6dc>Y^uw! $: pR0td6Qy>_ڞmGI?OB~ Yz욗 uydQ8ݽKF=YJтGȬ+[6TOjK^#̽bs8nqZ§3n=ڝ뢤ֽ(41²w}bSjm z&{mmI$ueu{A[dߜn+z ;Gofw;+SsW z Hb!H |]S yw>/6))*(ny;^/52fFEIW}U-QJ߯ }UIMA/__^]Ti8zO}]$%"׳׻))Tqi!1 &<| sƬ+aj-OT!| >Ax.$PǙ8^b6f!!ϳK$2=~H^@9&? {~}pp:?~xUrP`H0^~7<(q̋ BpXn !!p,nCPԉ XXb*C!q"jCp8j Cp2CPXbo>78Hs B!Pɐ܉2 ChXd,aXj PbCp6Cn W71ũP?#DE:Z摧nk3vt홤fgm:SjW`Y=P! T5 pN!d,7 B¡abEd7 pXn5 Pd2CHXj YVf(~1d"09$ v @JGɖ+cx)<Dpd&PL-7ku ;i PWVËd.8&I_y~#ٽC5N/ĒC$#qpuOD#NHa2i$܋Y!k I͜Z8y(#(.%Vpw۔ؽ'!{=IqzG^ x@vI]|DRwƳ"/G*/Öt""błE6Eỏt;C!*K !aXvtuGW<ҍfe8f$=zdٙG4Zbt!hRسr?er!X!: A#r&8!jCR&&!!2Hj37"m!n7 C!ad,an7d,:Cp5 C! Xd?/,8q 8n0ʓ1212d~NyXu0XbhXj !2 B!aaPCXq!,2Cwr յmCWb;tkQJlϦy'ri8C=Xj5 XXXj Cp Xd1 * aYPR2&5 a8BBHL$!y.C{( n-j^jNڤAl/eqfmê&^wF~ntwA`sR7GYo5H빆j-+8v=ܬR~j@r0w-/~ *B"Zf["ص"Z-IlB"!"r_Gܦ@N ]vWڈ鶽ge8'foKy5&gCOh4Z Z*?,) %(hNq: )#eo^5=pL9q6, ᳪ;Ұ'pq9*μrw-hv3^%%SybfNWt㵏q'a_{mE^7D aߐ!!_Є BHI !2{pcػXӍx'ٺ&R{^BMzvpdLaje P1 !b B!aaa7 4i Cԉ!P?LMK8p,5"Xq 5 !aj B!d*"d5 p2!2 C!d5 XXd7 C! B5Ş-*t'RHdu4*|JAGeZUq}pXϞXI2 »z*!p.)=vy /iokY睻 㰭vANC h#hS KZf p P cgH<= p\ۖq8W}ʅ}Ue쵔̃y Aٕ˃KWY:kE-{L&S8]x7s!Xz5Lـw!ږ#RKxvzK|5wFMixa:_)df8.} uI8a2񾓯9[\G7K)[8N0,o2A-s5AD;1/kQۼ,kks &L~m#m%G?ob뫿M\=|sT|1s c'"nZkYMt{ˢq]@R `uP GV .-hxyjbZ1B%QӔ=$.˞z')^%Z;׼Àg yfVOov*Ol7ǖ5;?+ү ^>]3V/dǁ\ Ä FQJ*c2vmuz0L͗ц[dr__}9bs4&uZGNFIhU Թ^S!-Ev :h9bhڠ~G 9~^[sxg) sm (Nfz#\L 2T7K.sROjܳ& •4qlEKPӺĴXHdޞL;XڑۋE;}VcuB8N ZAZ^Pdv/Cg&+K?,MLgZ 0Fi=(nܦɏ1L="v|X~:W C5 !%!$9."Əqr47ʹ513 ;&WYKrsܗ7'AKOI {mM_ϻпCaXd2BPXd*nCPj奇jDq"n0D7 B jChhBR&XjC!ai B,7 Cj!d,:͡n!a,,9Hi >zXd7 BțB1 CPj Cp,5 aa !adLBÙa7 5!nB!Xj ^){L STSjGh 4懞CP&C8XYbC!aCjC Fd$KEw &mG{'_Bu_{ׇw0ڸ -dk`F_4Ll1CyrpMe@!Ʀw+ٗ,5Έ6ihajڈoz;n?VfcG;.}u`o?~NP0B%$DSL4%4UACCKUUD1DEDSP@M4T11444Dđ$E5IEPP cc M.;4==(?6cA㲭\@bW<ЦF^K@R6ݟ\1_]>H :ߏ1dR좌FSvll=[ Mu[^;Zsmd p'%#0m b)&FO]dzzfKx&ɴ[w->Mi{):+Ң%_irv> O+V,s9.Z$wj-zjfCxlcaݶ٩l-U .?޳Zr}"|Orm> Y/g|?ݜz >8NP$~b9Rp^䄐OaJfѶ-(p+i5='L36*Cǧwkmdrv aH#hƇthh yp YJ`@cOrEbzذ63I|rƫ[ Ez rjV.h$@wvO$V^9,MVXNv4z1ZfZ}'9ܘwm[,Ig=.O[cn)'`cOF^[$ )_O>%@"!^曀l{&ckTRp?Dejz b3#ϫW#-75dqE"ׂx%^ޮ ;ŷ-G+ @R6J,?M9XnI9,t;r0D` !N" 0:H~{߯=bU_7ˠpHKo?J]:5w\BG@#>CŦ89Yc.*n} P@7ByAC1Yw&xoQo9nʘdXG$HSU}S=9 YZ9ʦc*)d|wlreqy{ǒ +R_t |oE1P>(kj$e0Z'LvzS4y. ՠX ٠q$U@y48!$:R%1ܘv | <0 [@"ch<9Dt1r;겼SdAײn - =y\UurvdQP 5J,(>p,lxGMR+Ls$@^Xkq.[0óԑSL43ffQoht(,_̀AdNbޘ8Q CB ,.,-[MC,[/jS}e efsˌ2ft_|Hз$"E^qKo"ؼnۮ[b%8<LcjmQlC7|j$ˮx$TnȒ~=S_cS~<³tbi99%(3YͮUf bO윇> a>x0cοo~vGn:/\(p0`%fi<>agT4 w]KI)OeIJ~fH!Ybn/^ۛJ a(q &nL-V2H  rhkHZr 4 q24#g77yzjZn)YfdD"hB6OQwg3 Vߌ3Dhnn[5T_FqN V'#;,'xcZu@A*ie"y%Ա5~.:Vh`>yxѸrܠ ~oRe߻f>m}u"վ*/UMm/F"֥5/&τ-4b%s0kuVI-3bbZ${#FFoH3 p::s*F>%"pP^9`Ѯ 2~Vf*̛wN` -A uq] $37~ ^qyKۏiȁ{PI`p`>5}8b[*!% "1wE0λK|p(Y+zfl渍iC N OϽFC={EO:#-B5MuwSĬYMg+B}~ an€כ\wCl$[˭ p\@$"&a\2΀-BYqy323G 65r{uv5 5-Q> 7i{snӲ+_>fysEވvwH1=񧸻"XV-`!h-P)tA=O/ᢡ~x@,O"^`:szVGqw)>,z`-$!k IwU{Kspn5Oq9]sD_:9 8Oǧ*ʍ#Gȹ5~zVn ] W!naЂY'f 4&2i=mZru1Y^sFYq@q5VVMOE5x1^ *n@F@m{0#zy4E.08%Ϥ[.%/h|@ChTDˊCΞqi9D〄 $o富2_#x邥 MA;#T}3K4?շpK= F&,ZQιnC'7#D@A6_=+Ee(n A@b$PH EňMpn&88l~}oɏD>i.:>aOP0j9O Y\1@E- RD@X+'5~6_3,[@yNkH[ $^v62$)ÐZP#wW0u(rMCFS0j i`9vվJm7=%\sw9Ǵy2翯#g xz?NNu^D8f,Nn@r;ul?FEwýcf}L-At(}t 7]摜>ޜo4,b+"nySv-+R7{GfpzyZo(/wjp\渴1%ԸvCY59@v# xxZT o$w zc ϜZICBc]ak^dptGi #R%BpS !g7ʹ/l|͞X@OBK'UJ ojvzZ){ _ |cM(J%z#vn3|!DK&#Cy>L{}fi;  Cj[3[ >0\ݼAW;ըQ ]~j<=$xm s.tZNJZF\042_+ہ 2Ѐd8 #yK27 j`kS͔Ÿe%y&fY]A6‚wy5~?*7^s;ms:@O & >O fEȆH6ˈgYݸc1 -}5Wvzh|J^++9:YD1/eobxnwLF|c TNhgixD7h_ѧw-Jm0m&[vNDa??t:O 0}9ykd+v}I900Ȁ6ⰻzy$#_QvfH#ۨ [~iOZV,^Eo> I=D{S}łA,)n]@ F|2(6{ dxT e+ sx+wK λ+ UBqn]{+]/k~ߌII GV1Bg6Ή@J#T5=V%$2J{%]OAJru CdRw}Ik?x+7 ǿ-RY!~GԀoLf=:EU>kn[fai}@xmeiHEx^Ehob.m`;,ezmү=yYi1 2ynPAo?+y CzK$Ĥv6YZ<fQoxr&TN_\ʼnÖ*/o;:!/\AEo<l֚}-Tj<  +?juͫswjt/0@/\>R,ڟȻަ;OlGX$jx5Jy-j4zmZRY uH^Cvao 1d@R_8,Iz-j/ jɐDpe?=g]ɝd^7{ϱ 6 \UL=n2*_1V6;lE1ƽ%i9hI&>̇LwY"߽(@$Xh$kof62G|P[dL*׳Ge=d4S6&VCjճ|23`VI_otW^ue @"ILKG? qN'lv6KMܖHp5oTH|4*.wAs1vb vLp~/ތuBf_dz-YEހn)RG=잆o\Ǘ3Jb0Vy{1o*OS8Lj;tk%Է1KP$sIg #W 'k %][٤рJ"?Echj`@CXc:iB}Cf睈jZDa 0/E];{^C @1\YV|%?}I+f ɟ*<>ُjs}$u elQ ( 6כ(p] 5=K}=I pCrrP붩յ^lZ/ NG_])},g/wEDeݥB*AA {d'D 6"ڿa` 0$l2SLX#ktN'\$Ⱦ,I\?I^^&6f,/-RU6aV"7@d a@  @~`y=Ɗ'}ܒlbSO\uN/ H^ݒc> ~Z_Ӂ"3L}מނK=;o[(gخGQ_zNwZ~$hS-qnI%j_H1n^`A?lYr]s3@SM]?ӂԻU]\0 ր" VC]= k\O !&]2OSknc#mU0P4e=5QiW".JC!jhǏ5NWE_{бA!@60\ث,*Z .soV]~#m.gH_w 雈OH\z~v21] M1Re@(3#hBH `q,𠬾AO"?# &g̉Xo.!1/ި"s|_f`ƯHFXhܙlk߅Nc|Ӱ^#%D1^De(Rb H?xr 7'`[*Xaf Wpw@Ag{?;QΛGt9'*Gh1o;@B`^r~ |!cBu֥+88WYXp2Ӽ&Tw_etxmD y~ =!Cmd۝`(?.]F{lVP@Z 65KtG8tl̶G+e*wZ;a~%| D7)(~4ɛ(b6|k9>8b8?[bXb@"i=KkƢia*qIKj8!WɯYd.Ox w4QhBgy0"%UU[W#iۮv]C~\ 1It4kV* `xU>>97!NYe|L7c75 2 3|2I\$߀T߅v6% Rkag -ix|ir{[h,:``: z0:s6{n~ԝm,/ `S?_ۡ-v;騗`@8;?$sSj6wY%E\6ai"¡5D;w4SQ"@W -1.L`nQV4ayQu:*} ?jϟL_5^ [ŲE60(G|K7یlB AyrP~Ǹwnk8_alidԕl:fU=n zMZ)}~wM+DQ1&;~@y*|y"D"?$>[ ~AWo"ju-7h@ IBK;?ך I{?xl֔e>ak"U: ToڠE۹C5 ͟lz(# ?5@WpC(kf#A*Ե43G7 =#eك4$^׵_,5]v _r꒿4q3a9&4?C&xT0([ߊ,6ჩuq ZEΛPe+6z>AR1(ڠ98OO[n%Hp=yFRB֧Ij€ek+u=GqDL"VY ^g:;jQA[_ VD /9?^3`6J^x0%IWQ\/95yUivݔ2hs^ Z-wF_~fw=*/5qY:P̣gp3zAlw*x|gQB:i?g$[4^}CޫmJM5>j]Z̧n.]> m0/ [^<FOeo^MWKAf9e.*$|uP_ l@z.`z9Xf3]yIWAM}Y!^^ݻǓgLH/ =]K1_@];?4}5Ű d-v*".<,S6,WZż5#4%,kM:KF&\9$-اR >.D  #99'E+ӬB+~H2@+Kn\8}2H @w$r: p%sUv\Lx.ь^ڃEumpkȽe#Wڗ2`/{|o/׌ <5}>1iCۣgI-'WF4#:.KeӘXshmUA}xcL̛(?EyMdRAο4[l.v'[{:^emo%`;VrX`Atzl"D-28YVNE)@ &ף߭ybz~ngL@Goy.8v XsWN7/YR}cI@5V~2=B gyήJ2 cZ4"h֍5[Bh }$ ӿ/~{E~Ss>}MvgfHb{twOkc 1,}8e<-Q5\l7aQvH=gNPdlc Ps.m0K_ d9%U\ڜ4Zjtw]pu½El*S1"E6ދ1owyw<F'f ,\nu]Nr>HF!JEe$.}^?9"T紴;b2+RjU^E/vGkv?5wAn5č?8)uJ ScI"b (mq ىL%fQ]]H7Kid1rdkg~1 8,psdGƩcA df|y/6Ny.hQ^s+ |P.Q u |^/l6;:cpE?,9;mc{^ݮɳx- k,- ".#Bnud9̙Vlo4 iġ,ip]Mݏ9D@~Pa ӛp-wJj]{nj5DF?3KZ.ne]==٠غ33Ć-hΪ }  " *NeP >sdMw?Cc/[6|{H[& zd.y-+>$ٵ?_|d؁ 0 @ K14J7Dv0Uwt 0O-PDV{k ·=ap˟ëׇ;-g7T{AXvn20=}+͘jx`ϐv7p]px=t<#,%+m7]{/ܰځ A kǗ홴r/[@{HuIY#c!  |dgcgŔN\+ zTPCNKM@_Ƨk\S}Z{+6}l˻N֬YZ/,u)}8K@:Tfn\0= ek>Km &2dn:1P$89t(uxW*B9jF&J-}<)-RbctY{S\Wf{dAܱyt1HPxu1 eQKTk5H, Pw]VՅz|Cl[y!` 6v>P(Q71`%'e,+F^oOcoׯ|ǵ}o:&+e|yy]З@F:|fŀE/IU% F47WxZUm+m/sz cHT0p~ySvC(Stϓs'"acѣdd3kDR [{jG~  2Ή@ig׭}QLZ&5? ..& BV0ېk}aqO奴@CVWrbiRɌKM(4 "o+13F\'q %XbAš*)JC褐Zg "|42o2ro7{̑kzÞ_r1n lqq wo粙|ߦ7~bIB_cHLn{5ϥgW)6|SV>`*dv7H^>eDv4.ٯ|qkk5ԩܔqzn_ywGqldC{1ro"6_/1ZkMmwa/҃a橓LM]|ohXzj߶Y-_y/vEЗ|nK '÷9@,:4qKsQ_)30_ѝgjRC=0N| }:{fmg!Rm4O- >=ۧͨ-Ma^cI˔72:>,aOMq<͉ќ9;%;uؙduwdv +p=.__znqԭk{_Dq -Ӽf.Oo!뻪.F :k}R?jG&PoY*|Q=NoM]yiUa {\5#TE_|5A~uyܒz* -_L%ڜ f\?kJ_RQ 7̉ϤsW*zR75$= 9 .MyH}m}5$.h_GϳTy8D͐|SUwM9#W`ހ;$#hPؼ8vZz !B(olU?)^'4`:ԶWv) BBC3"eÄch+4 쌂Et!6QT > IJsh];zMP teLRIpF]ћCi{vԢ(R<ػyx]/a GW~8:_3+sKk1- Œ JEH[2DM+6M ӥ^407굊t5SK r +{^m*-iCۓb, O{)B_)@w<ҵ"C2@zʚ$RǶrV/xpzkAI>z$'sjȤϯO:w㉣D"HGt$@Yv _I=l{ |^6<bSngݶyy~[%Iun~(aXvJ~[H0Ihg-uGrc_nsjHޤR=-U  dO'~vE~H&= ~}StaVe*W*H6X4ui)^;c _9i5YN+Ҁ $O $O=[ަlTy51:GʛcIPÙ~@(; Sy z]zht$%$>&JE{t_S*,\+OdlVBl<~6kdN+όI0N}O'Ʋ{e`GEWͨw+BmΗ6a\?E7?_.3rs$ ?B$@fQg] #I"HJb? OklZ+ZEO-VchMv,lЎ BuJEϝm8$gOV`G[OMqb_4Gxy[30rmnc& *1Vk ~䀹` @Js,yg`hاFq"V4Z*tyJڣ0, j=3 WG`"p=-GU/Ǭ[VS,RWClq<o6#5`z {o >5̂]i@PBXql CGP٦{ok>K#Y;Uտ@xy(:@U<־; z dk sDᾴ;.Jnz{ެGգe$a>7#`  %a]= 2e]OqG7ճ|NVLg@T&h\l;W63gpJJqL@ ל 8DϹ=uiwb໢ $/RVz}-jj/2UDzN _+[Igo 𾇿`S_Tq@%-qWYprE/Ӝ#rh~Q;\D=/:N}QGO=BP"v}p+@:4:)39{jRI3~'fVQ - njqtXkn]Im$wUgTH %؋~{VPHxE*u\=Ʊ/nwtNuC̻ SPZrEx>>#Sg55ڷGYcf]=ǿA"4X;KTUMj@G%HL8eBMx+,U)X-<B& EW x|{4@g|H|(Nm`s`+_*HRg%A|n@k'ݠl+jv;SPA0b-5rMdIJ(#c/-OtIT=O^ tSX(״cq/+)G (̓Ξ]dx\nB09{Z=D"$s1J;G譇>:$ g!Ix jU[ 1vYk,#m w{mX6ֶhְX6vneCdɾRdK$g+%)>^/V~FD`VF%/};'p3)>h31"9PPQS@DpWSˀ &yl !|K"H LI鏝Э軥Tʮ?"0zkDx1T>$>cT20ϵ1M6ڎEIQ l^\SKGsczP E w0/t@~Pmg`.p|IPP8G?l3BK eP:c\3wG[F tP pv!" c1U ve;GTDް00?o %,"qf ^ZuOo3Plxc0,iPC, %; lOH.B%7A^}t$K˻L mr,c#zD =c8ZSP*eJpt^@ uQxWc}H7_1زRod ڇ0k9xaX`A"r>R>m Q`7_:U~`T ,hT9Oy^.V:"聯k8m wY~Vj7n[98e@t벚4A!'O$cYIU8_U@oUn$y ҠI7ta< sܢ@ {yV MWÑ ٰΘ\Э;z,c_M6mx4a,unN9#?8`Dd{}#o.^U .tĞDT xєs5n(isCS:!ߌ樧bQi^{]aGٴe)l:njjPn!Q F"oX-JعaL@7Ƅ@w>Epj=zvc$Z8$? K<=co Z,G]ʑUly' Z> vDϫwqzQ:L Zӑy؅L%}處4LrBUyހmϰk /zً覎ת}UklT4a&l?aC?gሰQrPyqhhe`jޥyӤdS#;LnD@}"0ⲨVs'~ LA0>$"Mtŭ| 9?RY Ȁtu\㝬Ps(NuӻL[5#H>nmJW5gfYiI ># {?(L!if=;rl@G*?;\I%qрhM)T/$ F1[K &յ]}j>@A|J@)LI_f:SW< N?{$.[zcj\ތ@9J=tRw v ur.WMu:U׀۰G#Dߺ&LX 3:LW]j@p:`-)}QCa[CȌ U )(ҁ͍ק-3 Vm8 _x NUR# ctDp~VdlLr0PqxO ]0X%+Fڛt 3DT g$Uxŋ-Wpkjfnu/rǃ~AX.-8AZ1D0fI=4:AamMgLUOT wdN i$HJi/~}PLJ5]uHf$+P( S%+:w<7؊YAWȈFEzk-\ -Q4]]vK1B1r2huf)|| O@/gઞ9$'DǢ{ Oƕ-sje?yt*NrӶuIi5erai: ͨ2>wEXpu:ť:f)b$d8QHMo{^C$S6Q<0ڶ&AHr3[ݿB0,g?y}%BeãkFhҌ * T+sGs&ωْ*Pmӵx#m8vZ硓D]xP^8ɔMoc%A@'4̉*.Z6?^u8|N4Cq6O9EIjڂ ShouOF'bw%7|.R]s{Y{6Q!;F9-үQnZj/+@@SֵdzщCKIAUdqzv_t"X nt&wMeKMG\A LW8&X  {h;ޢHe#${BS f!Hc9 DMlUmsEƠTW{z3f.HRGkHp ʎWͲ6vQ/^:?x7)X?O>.d%T\uU c8m}xLZŮ Zr68[X {Ye_ǨKD!7dctea J0[4@s*pqʵh8}m˙wzPnFMqceMjf7ɗ﷟C H\-o:ǩZܳR]P萒a!D!}r vE'C͗NL,.\sH} n"Q[1 iPI>@E9X4ZtQK)n?vD^Ȼ "$v[Q?G~6I!PpZ`vmEg'8B0N5}޻,gŵ`0.fXMׁ]>ol^'hZ;d=:yuIp<#=UHaR4~&PP5LUosn+0o"ĝ%da6z n=gC}:ߒ9`zp}CcB }"APjq" <&;.p#voPs/i $-쩗|; tELx''T3;(SP p YUTxUroR4t I;-yd;O 9c7`wM:N(?HOۀ>4?IxzTiA ""M"OjϑP" UяJŐ$!R+C6ב`3g6fhJmfċXB>Gc0 ^'L}^}Rh:fXƸATR5}|rm4?դEk׳$  57[dWFC6S㫜to9۪gߧ%ʜi=g Sm s9>#{ҙ&$; gLG.er=X|fI0M{U g~ڞW]G//{*!2ɲHb`.CR h+)A!t=Hh7=mOV}ѱj6z4k,sBALP\S4{;A4]`5"Ma0 LÏ}i:ܰIF4ɀx, ZгbZ/:,g!ȐcU [xj-Lt1>1G*=_@q3Y-]-#=\|ض|mtVy$7@)1!}<>>ҼUY'S:kHl#!i)}9H{J1)!`(Ns>/'6IF'*zCmWe%ڮ?ҍ;P~϶j3^wZ SmD(H ټʦ@f.舘18 yɰybK˖[UʪZ>njƫ:4^{',mcvלT4N~, ߑƭ6eEL!BN c梊VX8У:H$/#`q >0 FoE(M}5}%GĐilwLbJh =j(6:d2A#PzX h QCQQ0 [C47`^7/hV}@:.QM{[mf9DQ?_bm&_2qO!PK4]6z,EUc$~9$2NF՝QɍB,ف 93_-I uyU,퐝]g57IUN( %f7 7-}kB֎7 h[$6;\M-F3zCns>/ G* tj>.}s&eE𧃏ji%Lg[Y,Gi+Dq(M} ]#m 8DhȐaQ'nY/įnkX$ܬRjѐkU3~}=*ϒ)fs_OHAwIS\ ÑT3z9zsOX~NaDiL $Sv盫ҶLh1Nl<~$2|HGf(pͫ0,x<$'b!e@gSHD!DdލQow8xƐ%.  OyO_IlOfMFo"*2*jbE'duiَ\ 3) levels(pbmc_small) WhichCells(pbmc_small, idents = c(1, 2), invert = TRUE) } \seealso{ \code{\link{FetchData}} } \concept{data-access} SeuratObject/man/RenameAssays.Rd0000644000176200001440000000127514520004144016300 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/seurat.R \name{RenameAssays} \alias{RenameAssays} \title{Rename assays in a \code{Seurat} object} \usage{ RenameAssays( object, assay.name = NULL, new.assay.name = NULL, verbose = TRUE, ... ) } \arguments{ \item{object}{A \code{Seurat} object} \item{assay.name}{original name of assay} \item{new.assay.name}{new name of assay} \item{verbose}{Whether to print messages} \item{...}{Named arguments as \code{old.assay = new.assay}} } \value{ \code{object} with assays renamed } \description{ Rename assays in a \code{Seurat} object } \examples{ RenameAssays(object = pbmc_small, RNA = 'rna') } \concept{seurat} SeuratObject/man/CheckGC.Rd0000644000176200001440000000053114473173564015152 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{CheckGC} \alias{CheckGC} \title{Conditional Garbage Collection} \usage{ CheckGC(option = "SeuratObject.memsafe") } \arguments{ \item{option}{...} } \value{ Invisibly returns \code{NULL} } \description{ Call \code{gc} only when desired } \concept{utils} SeuratObject/man/dim.Assay5.Rd0000644000176200001440000000132314520004144015614 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay5.R \name{dim.Assay5} \alias{dim.Assay5} \title{Feature and Cell Numbers} \usage{ \method{dim}{Assay5}(x) } \arguments{ \item{x}{An \code{\link{Assay5}} object} } \value{ A two-length numeric vector with the total number of features and cells in \code{x} } \description{ Feature and Cell Numbers } \seealso{ v5 Assay object, validity, and interaction methods: \code{\link{$.Assay5}()}, \code{\link{Assay5-class}}, \code{\link{Assay5-validity}}, \code{\link{[.Assay5}()}, \code{\link{[[.Assay5}()}, \code{\link{dimnames.Assay5}()}, \code{\link{merge.Assay5}()}, \code{\link{split.Assay5}()}, \code{\link{subset.Assay5}()} } \concept{assay5} SeuratObject/man/CreateCentroids.Rd0000644000176200001440000000132714520004201016753 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R \name{CreateCentroids} \alias{CreateCentroids} \title{Create a \code{\link[SeuratObject:Centroids-class]{Centroids}} Objects} \usage{ CreateCentroids(coords, nsides, radius, theta) } \arguments{ \item{coords}{The coordinates of cell/spot centroids} \item{nsides}{The number of sides to represent cells/spots; pass \code{\link[base]{Inf}} to plot as circles} \item{radius}{Radius of shapes when plotting} \item{theta}{Angle to adjust shapes when plotting} } \value{ A \code{\link[SeuratObject:Centroids-class]{Centroids}} object } \description{ Create a \code{\link[SeuratObject:Centroids-class]{Centroids}} Objects } \concept{spatial} SeuratObject/man/as.Centroids.Rd0000644000176200001440000000202314520004144016231 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/utils.R \name{as.Centroids} \alias{as.Centroids} \alias{as.Segmentation} \alias{as.Centroids.Segmentation} \alias{as.Segmentation.Centroids} \title{Convert Segmentation Layers} \usage{ as.Centroids(x, nsides = NULL, radius = NULL, theta = NULL, ...) as.Segmentation(x, ...) \method{as.Centroids}{Segmentation}(x, nsides = NULL, radius = NULL, theta = NULL, ...) \method{as.Segmentation}{Centroids}(x, ...) } \arguments{ \item{x}{An object} \item{nsides}{The number of sides to represent cells/spots; pass \code{\link[base]{Inf}} to plot as circles} \item{radius}{Radius of shapes when plotting} \item{theta}{Angle to adjust shapes when plotting} \item{...}{Arguments passed to other methods} } \value{ \code{as.Centroids}: A \code{\link[SeuratObject:Centroids-class]{Centroids}} object \code{as.Segmentation}: A \code{\link[SeuratObject:Segmentation-class]{Segmentation}} object } \description{ Convert Segmentation Layers } \concept{spatial} SeuratObject/man/PolyVtx.Rd0000644000176200001440000000227514520004144015333 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{PolyVtx} \alias{PolyVtx} \title{Polygon Vertices} \usage{ PolyVtx(n, r = 1L, xc = 0L, yc = 0L, t1 = 0) } \arguments{ \item{n}{Number of sides of the polygon} \item{r}{Radius of the polygon} \item{xc, yc}{X/Y coordinates for the center of the polygon} \item{t1}{Angle of the first vertex in degrees} } \value{ A \code{\link[base]{data.frame}} with \code{n} rows and two columns: \describe{ \item{\code{x}}{X positions of each coordinate} \item{\code{y}}{Y positions of each coordinate} } } \description{ Calculate the vertices of a regular polygon given the number of sides and its radius (distance from center to vertex). Also permits transforming the resulting coordinates by moving the origin and altering the initial angle } \examples{ coords <- PolyVtx(5, t1 = 90) coords if (requireNamespace("ggplot2", quietly = TRUE)) { ggplot2::ggplot(coords, ggplot2::aes(x = x, y = y)) + ggplot2::geom_polygon() } } \references{ \url{https://stackoverflow.com/questions/3436453/calculate-coordinates-of-a-regular-polygons-vertices} } \seealso{ \code{\link{Angles}} } \concept{angles} \concept{utils} \keyword{internal} SeuratObject/man/Assay-class.Rd0000644000176200001440000000312414520004144016063 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay.R \docType{class} \name{Assay-class} \alias{Assay-class} \alias{Assay} \title{The Assay Class} \description{ The Assay object is the basic unit of Seurat; each Assay stores raw, normalized, and scaled data as well as cluster information, variable features, and any other assay-specific metadata. Assays should contain single cell expression data such as RNA-seq, protein, or imputed expression data. } \section{Slots}{ \describe{ \item{\code{counts}}{Unnormalized data such as raw counts or TPMs} \item{\code{data}}{Normalized expression data} \item{\code{scale.data}}{Scaled expression data} \item{\code{assay.orig}}{Original assay that this assay is based off of. Used to track assay provenance} \item{\code{var.features}}{Vector of features exhibiting high variance across single cells} \item{\code{meta.features}}{Feature-level metadata} \item{\code{misc}}{A named list of unstructured miscellaneous data} \item{\code{key}}{A one-length character vector with the object's key; keys must be one or more alphanumeric characters followed by an underscore \dQuote{\code{_}} (regex pattern \dQuote{\code{\Sexpr[stage=build]{SeuratObject:::.KeyPattern()}}})} }} \seealso{ v3 Assay object, validity, and interaction methods: \code{\link{$.Assay}()}, \code{\link{Assay-validity}}, \code{\link{CreateAssayObject}()}, \code{\link{[.Assay}()}, \code{\link{[[.Assay}()}, \code{\link{dim.Assay}()}, \code{\link{dimnames.Assay}()}, \code{\link{merge.Assay}()}, \code{\link{split.Assay}()}, \code{\link{subset.Assay}()} } \concept{assay} SeuratObject/man/CheckLayersName.Rd0000644000176200001440000000066114520004144016701 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{CheckLayersName} \alias{CheckLayersName} \title{Check layers names for the input list} \usage{ CheckLayersName(matrix.list, layers.type = c("counts", "data")) } \arguments{ \item{matrix.list}{A list of matrices} \item{layers.type}{layers type, such as counts or data} } \description{ Check layers names for the input list } \concept{utils} SeuratObject/man/CreateSeuratObject.Rd0000644000176200001440000000604414520004144017422 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/seurat.R \name{CreateSeuratObject} \alias{CreateSeuratObject} \alias{CreateSeuratObject.default} \alias{CreateSeuratObject.Assay} \alias{CreateSeuratObject.Assay5} \title{Create a \code{Seurat} object} \usage{ CreateSeuratObject( counts, assay = "RNA", names.field = 1, names.delim = "_", meta.data = NULL, project = "CreateSeuratObject", ... ) \method{CreateSeuratObject}{default}( counts, assay = "RNA", names.field = 1L, names.delim = "_", meta.data = NULL, project = "SeuratProject", min.cells = 0, min.features = 0, ... ) \method{CreateSeuratObject}{Assay}( counts, assay = "RNA", names.field = 1L, names.delim = "_", meta.data = NULL, project = "SeuratProject", ... ) \method{CreateSeuratObject}{Assay5}( counts, assay = "RNA", names.field = 1L, names.delim = "_", meta.data = NULL, project = "SeuratProject", ... ) } \arguments{ \item{counts}{Either a \code{\link[base]{matrix}}-like object with unnormalized data with cells as columns and features as rows or an \code{\link{Assay}}-derived object} \item{assay}{Name of the initial assay} \item{names.field}{For the initial identity class for each cell, choose this field from the cell's name. E.g. If your cells are named as BARCODE_CLUSTER_CELLTYPE in the input matrix, set \code{names.field} to 3 to set the initial identities to CELLTYPE.} \item{names.delim}{For the initial identity class for each cell, choose this delimiter from the cell's column name. E.g. If your cells are named as BARCODE-CLUSTER-CELLTYPE, set this to \dQuote{-} to separate the cell name into its component parts for picking the relevant field.} \item{meta.data}{Additional cell-level metadata to add to the Seurat object. Should be a \code{\link[base]{data.frame}} where the rows are cell names and the columns are additional metadata fields. Row names in the metadata need to match the column names of the counts matrix.} \item{project}{\link{Project} name for the \code{Seurat} object} \item{...}{Arguments passed to other methods} \item{min.cells}{Include features detected in at least this many cells. Will subset the counts matrix as well. To reintroduce excluded features, create a new object with a lower cutoff} \item{min.features}{Include cells where at least this many features are detected} } \value{ A \code{\link{Seurat}} object } \description{ Create a \code{Seurat} object from raw data } \note{ In previous versions (<3.0), this function also accepted a parameter to set the expression threshold for a \sQuote{detected} feature (gene). This functionality has been removed to simplify the initialization process/assumptions. If you would still like to impose this threshold for your particular dataset, simply filter the input expression matrix before calling this function. } \examples{ \dontrun{ pbmc_raw <- read.table( file = system.file('extdata', 'pbmc_raw.txt', package = 'Seurat'), as.is = TRUE ) pbmc_small <- CreateSeuratObject(counts = pbmc_raw) pbmc_small } } \concept{seurat} SeuratObject/man/CellsByIdentities.Rd0000644000176200001440000000147014520004144017261 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/seurat.R \name{CellsByIdentities} \alias{CellsByIdentities} \title{Get cell names grouped by identity class} \usage{ CellsByIdentities(object, idents = NULL, cells = NULL, return.null = FALSE) } \arguments{ \item{object}{A Seurat object} \item{idents}{A vector of identity class levels to limit resulting list to; defaults to all identity class levels} \item{cells}{A vector of cells to grouping to} \item{return.null}{If no cells are requested, return a \code{NULL}; by default, throws an error} } \value{ A named list where names are identity classes and values are vectors of cells belonging to that class } \description{ Get cell names grouped by identity class } \examples{ CellsByIdentities(object = pbmc_small) } \concept{data-access} SeuratObject/man/subset.Assay5.Rd0000644000176200001440000000165514520004144016360 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay5.R \name{subset.Assay5} \alias{subset.Assay5} \title{Subset an Assay} \usage{ \method{subset}{Assay5}(x, cells = NULL, features = NULL, layers = NULL, ...) } \arguments{ \item{x}{An \code{\link{Assay5}} object} \item{cells}{Cell names} \item{features}{Feature names} \item{layers}{Layer to keep; defaults to all layers} \item{...}{Ignored} } \value{ \code{x} with just the cells and features specified by \code{cells} and \code{features} for the layers specified by \code{layers} } \description{ Subset an Assay } \seealso{ v5 Assay object, validity, and interaction methods: \code{\link{$.Assay5}()}, \code{\link{Assay5-class}}, \code{\link{Assay5-validity}}, \code{\link{[.Assay5}()}, \code{\link{[[.Assay5}()}, \code{\link{dim.Assay5}()}, \code{\link{dimnames.Assay5}()}, \code{\link{merge.Assay5}()}, \code{\link{split.Assay5}()} } \concept{assay5} SeuratObject/man/dot-Deprecate.Rd0000644000176200001440000000540614520004144016365 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{.Deprecate} \alias{.Deprecate} \title{Deprecate Functions and Arguments} \usage{ .Deprecate( when, what, with = NULL, ..., pkg = NULL, env = missing_arg(), user_env = missing_arg() ) } \arguments{ \item{when}{A string giving the version when the behaviour was deprecated.} \item{what}{A string describing what is deprecated: \itemize{ \item Deprecate a whole function with \code{"foo()"}. \item Deprecate an argument with \code{"foo(arg)"}. \item Partially deprecate an argument with \code{"foo(arg = 'must be a scalar integer')"}. \item Deprecate anything else with a custom message by wrapping it in \code{I()}. } You can optionally supply the namespace: \code{"ns::foo()"}, but this is usually not needed as it will be inferred from the caller environment.} \item{with}{An optional string giving a recommended replacement for the deprecated behaviour. This takes the same form as \code{what}.} \item{...}{ Arguments passed on to \code{\link[lifecycle:deprecate_soft]{lifecycle::deprecate_soft}} \describe{ \item{\code{details}}{In most cases the deprecation message can be automatically generated from \code{with}. When it can't, use \code{details} to provide a hand-written message. \code{details} can either be a single string or a character vector, which will be converted to a \link[cli:cli_bullets]{bulleted list}. By default, info bullets are used. Provide a named vectors to override.} \item{\code{id}}{The id of the deprecation. A warning is issued only once for each \code{id}. Defaults to the generated message, but you should give a unique ID when the message in \code{details} is built programmatically and depends on inputs, or when you'd like to deprecate multiple functions but warn only once for all of them.} \item{\code{env,user_env}}{Pair of environments that define where \verb{deprecate_*()} was called (used to determine the package name) and where the function called the deprecating function was called (used to determine if \code{deprecate_soft()} should message). These are only needed if you're calling \verb{deprecate_*()} from an internal helper, in which case you should forward \code{env = caller_env()} and \code{user_env = caller_env(2)}.} }} \item{pkg}{Name of package to use for comparison} \item{env, user_env}{Managed internally by \code{.Deprecate()}} } \value{ Run for its side effect and invisibly returns \code{NULL} } \description{ Provides automatic deprecation and defunctation of functions and arguments; } \seealso{ \code{\link[lifecycle:deprecate_soft]{lifecycle::deprecate_soft}()} \code{\link[lifecycle:deprecate_warn]{lifecycle::deprecate_warn}()} \code{\link[lifecycle:deprecate_stop]{lifecycle::deprecate_stop}()} } \keyword{internal} SeuratObject/man/Cells.Rd0000644000176200001440000000237614520004144014752 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/default.R, R/assay5.R, % R/dimreduc.R, R/neighbor.R \name{Cells} \alias{Cells} \alias{Features} \alias{Cells.default} \alias{Cells.Assay5} \alias{Features.Assay5} \alias{Cells.DimReduc} \alias{Cells.Neighbor} \title{Cell and Feature Names} \usage{ Cells(x, ...) Features(x, ...) \method{Cells}{default}(x, ...) \method{Cells}{Assay5}(x, layer = NULL, simplify = TRUE, ...) \method{Features}{Assay5}(x, layer = NULL, simplify = TRUE, ...) \method{Cells}{DimReduc}(x, ...) \method{Cells}{Neighbor}(x, ...) } \arguments{ \item{x}{An object} \item{...}{Arguments passed to other methods} \item{layer}{Layer to pull cells/features for; defaults to default layer; if \code{NA}, returns all cells for the assay} \item{simplify}{Simplify the cell/feature names into a single vector; if \code{FALSE}, separates each cell/feature names by layer} } \value{ \code{Cell}: A vector of cell names \code{Features}: A vector of feature names } \description{ Get the cell and feature names of an object } \examples{ Cells(x = pbmc_small) } \seealso{ \code{\link{dimnames.Assay5}()}, \code{\link{dimnames.Assay}()}, \code{\link{dimnames.Seurat}()} } \concept{data-access} \concept{dimnames} SeuratObject/man/sub-subset-Seurat.Rd0000644000176200001440000000442614520004144017243 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/seurat.R \name{[[<-,Seurat} \alias{[[<-,Seurat} \alias{[[<-.Seurat} \alias{\S4method{[[<-}{Seurat,character,missing,Assay}} \alias{[[<-,Seurat,character,missing,Assay-method} \alias{[[<-,Seurat,character,missing,Assay5-method} \alias{[[<-,Seurat,character,missing,DimReduc-method} \alias{[[<-,Seurat,character,missing,Graph-method} \alias{[[<-,Seurat,character,missing,Neighbor-method} \alias{[[<-,Seurat,character,missing,SeuratCommand-method} \alias{[[<-,Seurat,character,missing,SpatialImage-method} \title{Add Subobjects} \usage{ \S4method{[[}{Seurat,character,missing,Assay}(x, i, j, ...) <- value \S4method{[[}{Seurat,character,missing,Assay5}(x, i, j, ...) <- value \S4method{[[}{Seurat,character,missing,DimReduc}(x, i, j, ...) <- value \S4method{[[}{Seurat,character,missing,Graph}(x, i, j, ...) <- value \S4method{[[}{Seurat,character,missing,Neighbor}(x, i, j, ...) <- value \S4method{[[}{Seurat,character,missing,SeuratCommand}(x, i, j, ...) <- value \S4method{[[}{Seurat,character,missing,SpatialImage}(x, i, j, ...) <- value } \arguments{ \item{x}{A \code{\link{Seurat}} object} \item{i}{Name to add subobject as} \item{j}{Ignored} \item{...}{Ignored} \item{value}{A valid subobject (eg. a \link[=Assay]{v3} or \link[=Assay5]{v5} assay, or a \link[=DimReduc]{dimensional reduction})} } \value{ \code{x} with \code{value} added as \code{i} } \description{ Add subobjects containing expression, dimensional reduction, or other containerized data to a \code{\link{Seurat}} object. Subobjects can be accessed with \code{\link[=[[.Seurat]{[[}} and manipulated directly within the \code{Seurat} object or used independently } \seealso{ See \link[=[[.Seurat]{here} for pulling subobjects using \code{[[}, \link[=$.Seurat]{here} for adding metadata with \code{[[<-}, and \link[=[[<-,Seurat,NULL]{here} for removing subobjects and cell-level meta data with \code{[[<-} Seurat object, validity, and interaction methods \code{\link{$.Seurat}()}, \code{\link{Seurat-class}}, \code{\link{Seurat-validity}}, \code{\link{[[.Seurat}()}, \code{\link{[[<-,Seurat,NULL}}, \code{\link{dim.Seurat}()}, \code{\link{dimnames.Seurat}()}, \code{\link{merge.Seurat}()}, \code{\link{names.Seurat}()}, \code{\link{subset.Seurat}()} } \concept{seurat} SeuratObject/man/IsNamedList.Rd0000644000176200001440000000166014520004144016057 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{IsNamedList} \alias{IsNamedList} \title{Check List Names} \usage{ IsNamedList(x, all.unique = TRUE, allow.empty = FALSE, pass.zero = FALSE) } \arguments{ \item{x}{A list} \item{all.unique}{Require that all names are unique from one another} \item{allow.empty}{Allow empty (\code{nchar = 0}) names} \item{pass.zero}{Pass on zero-length lists} } \value{ \code{TRUE} if ..., otherwise \code{FALSE} } \description{ Check to see if a list has names; also check to enforce that all names are present and unique } \examples{ IsNamedList(list()) IsNamedList(list(), pass.zero = TRUE) IsNamedList(list(1, 2, 3)) IsNamedList(list(a = 1, b = 2, c = 3)) IsNamedList(list(a = 1, 2, c = 3)) IsNamedList(list(a = 1, 2, c = 3), allow.empty = TRUE) IsNamedList(list(a = 1, a = 2, a = 3)) IsNamedList(list(a = 1, a = 2, a = 3), all.unique = FALSE) } \concept{utils} SeuratObject/man/Simplify.Rd0000644000176200001440000000143014520004201015464 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/utils.R \name{Simplify} \alias{Simplify} \alias{Simplify.Spatial} \title{Simplify Geometry} \usage{ Simplify(coords, tol, topologyPreserve = TRUE) \method{Simplify}{Spatial}(coords, tol, topologyPreserve = TRUE) } \arguments{ \item{coords}{A `Segmentation` object} \item{tol}{Numerical tolerance value to be used by the Douglas-Peuker algorithm} \item{topologyPreserve}{Logical determining if the algorithm should attempt to preserve the topology of the original geometry} } \value{ A simplified version of \code{coords} A `Segmentation` object with simplified segmentation vertices } \description{ Simplify Geometry Simplify segmentations by reducing the number of vertices } \concept{spatial} SeuratObject/man/AttachDeps.Rd0000644000176200001440000000156014520004144015722 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{AttachDeps} \alias{AttachDeps} \title{Attach Required Packages} \usage{ AttachDeps(deps) } \arguments{ \item{deps}{A character vector of packages to attach} } \value{ Invisibly returns \code{NULL} } \description{ Helper function to attach required packages. Detects if a package is already attached and if so, skips it. Should be called in \code{\link[base]{.onAttach}} } \section{Lifecycle}{ \Sexpr[stage=build,results=rd]{lifecycle::badge("superseded")} \code{AttachDeps} has been superseded as of \pkg{SeuratObject} v5.0.0; as an alternative, list dependencies in the \code{Depends} section of \code{DESCRIPTION} } \examples{ # Use in your .onAttach hook if (FALSE) { .onAttach <- function(libname, pkgname) { AttachDeps(c("SeuratObject", "rlang")) } } } \concept{utils} SeuratObject/man/Misc-StdAssay.Rd0000644000176200001440000000117114520004144016324 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay5.R \name{Misc-StdAssay} \alias{Misc-StdAssay} \alias{Misc.StdAssay} \alias{Misc<-.StdAssay} \title{Get and set miscellaneous data} \usage{ \method{Misc}{StdAssay}(object, slot = NULL, ...) \method{Misc}{StdAssay}(object, slot, ...) <- value } \arguments{ \item{object}{An object} \item{slot}{Name of specific bit of meta data to pull} \item{...}{Arguments passed to other methods} \item{value}{Data to add} } \value{ Miscellaneous data An object with miscellaneous data added } \description{ Get and set miscellaneous data } \keyword{internal} SeuratObject/man/dot-DollarNames.Assay.Rd0000644000176200001440000000113314520004144017742 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay.R \name{.DollarNames.Assay} \alias{.DollarNames.Assay} \title{Dollar-sign Autocompletion} \usage{ \method{.DollarNames}{Assay}(x, pattern = "") } \arguments{ \item{x}{An \code{\link{Assay}} object} \item{pattern}{ A regular expression. Only matching names are returned. } } \value{ The layer name matches for \code{pattern} } \description{ Autocompletion for \code{$} access on an \code{\link{Assay}} object } \seealso{ \code{\link[utils:.DollarNames]{utils::.DollarNames}} } \concept{assay} \keyword{internal} SeuratObject/man/LogSeuratCommand.Rd0000644000176200001440000000155114520004144017106 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/command.R \name{LogSeuratCommand} \alias{LogSeuratCommand} \title{Log a command} \usage{ LogSeuratCommand(object, return.command = FALSE) } \arguments{ \item{object}{Name of Seurat object} \item{return.command}{Return a \code{\link{SeuratCommand}} object instead} } \value{ If \code{return.command}, returns a \code{\link{SeuratCommand}} object; otherwise, returns the Seurat object with command stored } \description{ Logs command run, storing the name, timestamp, and argument list. Stores in the Seurat object } \seealso{ \code{\link{Command}} Command log object and interaction methods \code{\link{$.SeuratCommand}()}, \code{\link{.DollarNames.SeuratCommand}()}, \code{\link{SeuratCommand-class}}, \code{\link{[.SeuratCommand}()}, \code{\link{as.list.SeuratCommand}()} } \concept{command} SeuratObject/man/show-StdAssay-method.Rd0000644000176200001440000000147514520004144017676 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay5.R \name{show,StdAssay-method} \alias{show,StdAssay-method} \title{V5 Assay Overview} \usage{ \S4method{show}{StdAssay}(object) } \arguments{ \item{object}{A v5 Assay} } \value{ Prints summary to \code{\link[base]{stdout}} and invisibly returns \code{NULL} } \description{ Overview of a \code{\link{StdAssay}} object } \seealso{ v5 Standard Assay object, validity, and interaction methods \code{\link{$.StdAssay}()}, \code{\link{.DollarNames.StdAssay}()}, \code{\link{StdAssay-class}}, \code{\link{StdAssay-validity}}, \code{\link{[.StdAssay}()}, \code{\link{[[.StdAssay}()}, \code{\link{dim.StdAssay}()}, \code{\link{dimnames.StdAssay}()}, \code{\link{split.StdAssay}()}, \code{\link{subset.StdAssay}()} } \concept{stdassay} \keyword{internal} SeuratObject/man/subset.Seurat.Rd0000644000176200001440000000335614520007625016465 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/seurat.R \name{subset.Seurat} \alias{subset.Seurat} \alias{subset} \alias{[.Seurat} \title{Subset \code{Seurat} Objects} \usage{ \method{subset}{Seurat}( x, subset, cells = NULL, features = NULL, idents = NULL, return.null = FALSE, ... ) \method{[}{Seurat}(x, i, j, ...) } \arguments{ \item{x}{A \code{\link{Seurat}} object} \item{subset}{Logical expression indicating features/variables to keep} \item{cells, j}{A vector of cell names or indices to keep} \item{features, i}{A vector of feature names or indices to keep} \item{idents}{A vector of identity classes to keep} \item{return.null}{If no cells are requested, return a \code{NULL}; by default, throws an error} \item{...}{Arguments passed to \code{\link{WhichCells}}} } \value{ \code{subset}: A subsetted \code{Seurat} object \code{[}: object \code{x} with features \code{i} and cells \code{j} } \description{ Subset \code{Seurat} Objects } \examples{ # `subset` examples subset(pbmc_small, subset = MS4A1 > 4) subset(pbmc_small, subset = `DLGAP1-AS1` > 2) subset(pbmc_small, idents = '0', invert = TRUE) subset(pbmc_small, subset = MS4A1 > 3, slot = 'counts') subset(pbmc_small, features = VariableFeatures(object = pbmc_small)) # `[` examples pbmc_small[VariableFeatures(object = pbmc_small), ] pbmc_small[, 1:10] } \seealso{ \code{\link{WhichCells}} Seurat object, validity, and interaction methods \code{\link{$.Seurat}()}, \code{\link{Seurat-class}}, \code{\link{Seurat-validity}}, \code{\link{[[.Seurat}()}, \code{\link{[[<-,Seurat,NULL}}, \code{\link{[[<-,Seurat}}, \code{\link{dim.Seurat}()}, \code{\link{dimnames.Seurat}()}, \code{\link{merge.Seurat}()}, \code{\link{names.Seurat}()} } \concept{seurat} SeuratObject/man/merge.DimReduc.Rd0000644000176200001440000000204114520004144016467 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/dimreduc.R \name{merge.DimReduc} \alias{merge.DimReduc} \title{Merge Dimensional Reductions} \usage{ \method{merge}{DimReduc}(x = NULL, y = NULL, add.cell.ids = NULL, ...) } \arguments{ \item{x}{A \code{\link{DimReduc}} object} \item{y}{One or more \code{\link{DimReduc}} objects} \item{add.cell.ids}{A character vector equal to the number of objects provided to append to all cell names; if \code{TRUE}, uses \code{labels} as \code{add.cell.ids}} \item{...}{Ignored} } \value{ A new \code{DimReduc} object with data merged from \code{c(x, y)} } \description{ Merge two or more \link[=DimReduc]{dimensional reduction} together } \seealso{ Dimensional reduction object, validity, and interaction methods \code{\link{CreateDimReducObject}()}, \code{\link{DimReduc-class}}, \code{\link{DimReduc-validity}}, \code{\link{[.DimReduc}()}, \code{\link{[[.DimReduc}()}, \code{\link{dim.DimReduc}()}, \code{\link{print.DimReduc}()}, \code{\link{subset.DimReduc}()} } \concept{dimreduc} SeuratObject/man/dot-BPMatrixMode.Rd0000644000176200001440000000136514520004144016764 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{.BPMatrixMode} \alias{.BPMatrixMode} \title{\pkg{BPCells} Matrix Mode} \usage{ .BPMatrixMode(object, simplify = FALSE) } \arguments{ \item{object}{An \code{IterableMatrix}} \item{simplify}{Return \dQuote{\code{disk}} for on-disk matrices} } \value{ One of the following, depending on the mode of \code{object}: \itemize{ \item \dQuote{\code{memory}} \item \dQuote{\code{file}} \item \dQuote{\code{directory}} } If \code{simplify} is \code{TRUE}, returns \dQuote{\code{disk}} instead of \dQuote{\code{file}} or \dQuote{\code{directory}} } \description{ Get the mode (on-disk, in-memory) of an \code{IterableMatrix} object from \pkg{BPCells} } \keyword{internal} SeuratObject/man/Seurat-class.Rd0000644000176200001440000000447014520004144016253 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/seurat.R \docType{class} \name{Seurat-class} \alias{Seurat-class} \alias{Seurat} \title{The Seurat Class} \description{ The Seurat object is a representation of single-cell expression data for R; each Seurat object revolves around a set of cells and consists of one or more \code{\link{Assay}} objects, or individual representations of expression data (eg. RNA-seq, ATAC-seq, etc). These assays can be reduced from their high-dimensional state to a lower-dimension state and stored as \code{\link{DimReduc}} objects. Seurat objects also store additional metadata, both at the cell and feature level (contained within individual assays). The object was designed to be as self-contained as possible, and easily extendable to new methods. } \section{Slots}{ \describe{ \item{\code{assays}}{A list of assays for this project} \item{\code{meta.data}}{Contains meta-information about each cell, starting with number of features detected (nFeature) and the original identity class (orig.ident); more information is added using \code{\link{AddMetaData}}} \item{\code{active.assay}}{Name of the active, or default, assay; settable using \code{\link{DefaultAssay}}} \item{\code{active.ident}}{The active cluster identity for this Seurat object; settable using \code{\link{Idents}}} \item{\code{graphs}}{A list of \code{\link{Graph}} objects} \item{\code{neighbors}}{...} \item{\code{reductions}}{A list of dimensional reduction objects for this object} \item{\code{images}}{A list of spatial image objects} \item{\code{project.name}}{Name of the project} \item{\code{misc}}{A list of miscellaneous information} \item{\code{version}}{Version of Seurat this object was built under} \item{\code{commands}}{A list of logged commands run on this \code{Seurat} object} \item{\code{tools}}{A list of miscellaneous data generated by other tools, should be filled by developers only using \code{\link{Tool}<-}} }} \seealso{ Seurat object, validity, and interaction methods \code{\link{$.Seurat}()}, \code{\link{Seurat-validity}}, \code{\link{[[.Seurat}()}, \code{\link{[[<-,Seurat,NULL}}, \code{\link{[[<-,Seurat}}, \code{\link{dim.Seurat}()}, \code{\link{dimnames.Seurat}()}, \code{\link{merge.Seurat}()}, \code{\link{names.Seurat}()}, \code{\link{subset.Seurat}()} } \concept{seurat} SeuratObject/man/sub-sub-.StdAssay.Rd0000644000176200001440000000434014520004144017070 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay5.R \name{[[.StdAssay} \alias{[[.StdAssay} \alias{head.StdAssay} \alias{tail.StdAssay} \alias{[[<-,StdAssay,character,missing,data.frame-method} \alias{[[<-,StdAssay,missing,missing,data.frame-method} \alias{[[<-,StdAssay,character,missing,factor-method} \alias{[[<-,StdAssay,character,missing,NULL-method} \alias{[[<-,StdAssay,character,missing,vector-method} \alias{[[<-,StdAssay,numeric,missing,ANY-method} \alias{[[<-,StdAssay,missing,missing,NULL-method} \title{Feature-Level Meta Data} \usage{ \method{[[}{StdAssay}(x, i, j, ..., drop = FALSE) \method{head}{StdAssay}(x, n = 10L, ...) \method{tail}{StdAssay}(x, n = 10L, ...) \S4method{[[}{StdAssay,character,missing,data.frame}(x, i, j, ...) <- value \S4method{[[}{StdAssay,missing,missing,data.frame}(x, i, j, ...) <- value \S4method{[[}{StdAssay,character,missing,factor}(x, i, j, ...) <- value \S4method{[[}{StdAssay,character,missing,`NULL`}(x, i, j, ...) <- value \S4method{[[}{StdAssay,character,missing,vector}(x, i, j, ...) <- value \S4method{[[}{StdAssay,numeric,missing,ANY}(x, i, j, ...) <- value \S4method{[[}{StdAssay,missing,missing,`NULL`}(x, i, j, ...) <- value } \arguments{ \item{x}{An \code{\link{Assay5}} object} \item{i}{Name of feature-level meta data to fetch or add} \item{j}{Ignored} \item{...}{Ignored} \item{drop}{See \code{\link{drop}}} \item{n}{Number of meta data rows to show} \item{value}{Feature-level meta data to add} } \value{ \code{[[}: The feature-level meta data for \code{i} \code{[[<-}: \code{x} with \code{value} added as \code{i} in feature-level meta data \code{head}: The first \code{n} rows of feature-level meta data \code{tail}: the last \code{n} rows of feature-level meta data } \description{ Get and set feature-level meta data } \seealso{ v5 Standard Assay object, validity, and interaction methods \code{\link{$.StdAssay}()}, \code{\link{.DollarNames.StdAssay}()}, \code{\link{StdAssay-class}}, \code{\link{StdAssay-validity}}, \code{\link{[.StdAssay}()}, \code{\link{dim.StdAssay}()}, \code{\link{dimnames.StdAssay}()}, \code{\link{show,StdAssay-method}}, \code{\link{split.StdAssay}()}, \code{\link{subset.StdAssay}()} } \concept{stdassay} \keyword{internal} SeuratObject/man/split.Assay.Rd0000644000176200001440000000307214520004144016114 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay.R \name{split.Assay} \alias{split.Assay} \title{Split an Assay} \usage{ \method{split}{Assay}(x, f, drop = FALSE, layers = NA, ...) } \arguments{ \item{x}{An \code{\link{Assay}} object} \item{f}{a \sQuote{factor} in the sense that \code{\link[base]{as.factor}(f)} defines the grouping, or a list of such factors in which case their interaction is used for the grouping. If \code{x} is a data frame, \code{f} can also be a formula of the form \code{ ~ g} to split by the variable \code{g}, or more generally of the form \code{ ~ g1 + \dots + gk} to split by the interaction of the variables \code{g1}, \dots, \code{gk}, where these variables are evaluated in the data frame \code{x} using the usual non-standard evaluation rules.} \item{drop}{logical indicating if levels that do not occur should be dropped (if \code{f} is a \code{factor} or a list).} \item{layers}{Names of layers to include in the split; pass \code{NA} for all layers; pass \code{NULL} for the \link[=DefaultLayer]{default layer}} \item{...}{Ignored} } \value{ Returns a v5 assay with splitted layers } \description{ Split an Assay } \seealso{ v3 Assay object, validity, and interaction methods: \code{\link{$.Assay}()}, \code{\link{Assay-class}}, \code{\link{Assay-validity}}, \code{\link{CreateAssayObject}()}, \code{\link{[.Assay}()}, \code{\link{[[.Assay}()}, \code{\link{dim.Assay}()}, \code{\link{dimnames.Assay}()}, \code{\link{merge.Assay}()}, \code{\link{subset.Assay}()} } \concept{assay} SeuratObject/man/split.Assay5.Rd0000644000176200001440000000562414520004144016206 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay5.R \name{split.Assay5} \alias{split.Assay5} \title{Split an Assay} \usage{ \method{split}{Assay5}( x, f, drop = FALSE, layers = c("counts", "data"), ret = c("assay", "multiassays", "layers"), ... ) } \arguments{ \item{x}{An \code{\link{Assay5}} object} \item{f}{a \sQuote{factor} in the sense that \code{\link[base]{as.factor}(f)} defines the grouping, or a list of such factors in which case their interaction is used for the grouping. If \code{x} is a data frame, \code{f} can also be a formula of the form \code{ ~ g} to split by the variable \code{g}, or more generally of the form \code{ ~ g1 + \dots + gk} to split by the interaction of the variables \code{g1}, \dots, \code{gk}, where these variables are evaluated in the data frame \code{x} using the usual non-standard evaluation rules.} \item{drop}{logical indicating if levels that do not occur should be dropped (if \code{f} is a \code{factor} or a list).} \item{layers}{Names of layers to include in the split; pass \code{NA} for all layers; pass \code{NULL} for the \link[=DefaultLayer]{default layer}} \item{ret}{Type of return value; choose from: \itemize{ \item \dQuote{\code{assay}}: a single \code{\link{Assay5}} object \item \dQuote{\code{multiassay}}: a list of \code{\link{Assay5}} objects \item \dQuote{\code{layers}}: a list of layer matrices }} \item{...}{Ignored} } \value{ Depends on the value of \code{ret}: \itemize{ \item \dQuote{\code{assay}}: \code{x} with the layers requested in \code{layers} split based on \code{f}; all other layers are left as-is \item \dQuote{\code{multiassay}}: a list of \code{\link{Assay5}} objects; the list contains one value per split and each assay contains only the layers requested in \code{layers} with the \link[=Key]{key} set to the split \item \dQuote{\code{layers}}: a list of matrices of length \code{length(assays) * length(unique(f))}; the list is named as \dQuote{\code{layer.split}} } } \description{ Split an Assay } \section{Progress Updates with \pkg{progressr}}{ This function uses \href{https://cran.r-project.org/package=progressr}{\pkg{progressr}} to render status updates and progress bars. To enable progress updates, wrap the function call in \code{\link[progressr]{with_progress}} or run \code{\link[progressr:handlers]{handlers(global = TRUE)}} before running this function. For more details about \pkg{progressr}, please read \href{https://progressr.futureverse.org/articles/progressr-intro.html}{\code{vignette("progressr-intro")}} } \seealso{ v5 Assay object, validity, and interaction methods: \code{\link{$.Assay5}()}, \code{\link{Assay5-class}}, \code{\link{Assay5-validity}}, \code{\link{[.Assay5}()}, \code{\link{[[.Assay5}()}, \code{\link{dim.Assay5}()}, \code{\link{dimnames.Assay5}()}, \code{\link{merge.Assay5}()}, \code{\link{subset.Assay5}()} } \concept{assay5} SeuratObject/man/LogMap-class.Rd0000644000176200001440000000552314520004144016167 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/logmap.R \docType{class} \name{LogMap} \alias{LogMap} \alias{[[,LogMap,character,missing-method} \alias{[[,LogMap,missing,missing-method} \alias{[[,LogMap,NULL,missing-method} \alias{[[<-,LogMap,character,missing,character-method} \alias{[[<-,LogMap,character,missing,integer-method} \alias{[[<-,LogMap,character,missing,NULL-method} \alias{[[<-,LogMap,character,missing,numeric-method} \alias{LogMap-class} \title{A Logical Map} \usage{ LogMap(y) \S4method{[[}{LogMap,character,missing}(x, i, j, ...) \S4method{[[}{LogMap,missing,missing}(x, i, j, ...) \S4method{[[}{LogMap,`NULL`,missing}(x, i, j, ...) \S4method{[[}{LogMap,character,missing,character}(x, i, j, ...) <- value \S4method{[[}{LogMap,character,missing,integer}(x, i, j, ...) <- value \S4method{[[}{LogMap,character,missing,`NULL`}(x, i, j, ...) <- value \S4method{[[}{LogMap,character,missing,numeric}(x, i, j, ...) <- value } \arguments{ \item{y}{A character vector} \item{x}{A \code{LogMap} object} \item{i}{A character vector of length 1, or \code{NULL}} \item{j}{Not used} \item{...}{Ignored} \item{value}{A character or integer vector of values to record in the map for \code{i}, or \code{NULL} to remove the record for \code{i}} } \value{ \code{LogMap}: A new \code{LogMap} object with zero columns and \code{length(x = x)} rows; rownames are set to \code{x} \code{[[}: if \code{i} is a character vector, the rownames that are mapped to \code{i}; otherwise the rownames of \code{x} \code{[[<-}: If \code{value} is \code{NULL}, then \code{x} without the observations for \code{i}; otherwise, \code{x} with a new column for \code{i} recording a \code{TRUE} for all values present in \code{value} } \description{ A simple container for storing mappings of values using logical matrices. Keeps track of which values (rows) are present in which observations (columns). \code{LogMap} objects can be created with \code{LogMap()}; queries can be performed with \code{[[} and observations can be added or removed with \code{[[<-} } \section{Slots}{ \describe{ \item{\code{.Data}}{A logical matrix with at least one row} }} \examples{ # Create a LogMap map <- LogMap(letters[1:10]) map # Get the names of values in the LogMap map[[NULL]] rownames(map) # Add an observation to the LogMap map[['obs']] <- c(1, 3, 7) map[['entry']] <- c(2, 7, 10) map # Get the names of observations in the LogMap colnames(map) # Fetch an observation from the LogMap map[['obs']] # Get the full logical matrix map[[]] # Remove an observation from the LogMap map[['obs']] <- NULL map[['entry']] <- NULL map } \seealso{ Logical map objects, validity, and interaction methods: \code{\link{LogMap-validity}}, \code{\link{as.matrix.LogMap}()}, \code{\link{droplevels.LogMap}()}, \code{\link{intersect.LogMap}()}, \code{\link{labels.LogMap}()} } \concept{logmap} SeuratObject/man/AddMetaData.Rd0000644000176200001440000000266314520004144016000 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/assay.R, R/assay5.R, R/seurat.R \name{AddMetaData} \alias{AddMetaData} \alias{SeuratAccess} \alias{AddMetaData.Assay} \alias{AddMetaData.Assay5} \alias{AddMetaData.Seurat} \title{Add in metadata associated with either cells or features.} \usage{ AddMetaData(object, metadata, col.name = NULL) \method{AddMetaData}{Assay}(object, metadata, col.name = NULL) \method{AddMetaData}{Assay5}(object, metadata, col.name = NULL) \method{AddMetaData}{Seurat}(object, metadata, col.name = NULL) } \arguments{ \item{object}{An object} \item{metadata}{A vector, list, or data.frame with metadata to add} \item{col.name}{A name for meta data if not a named list or data.frame} } \value{ \code{object} with metadata added } \description{ Adds additional data to the object. Can be any piece of information associated with a cell (examples include read depth, alignment rate, experimental batch, or subpopulation identity) or feature (ENSG name, variance). To add cell level information, add to the Seurat object. If adding feature-level metadata, add to the Assay object (e.g. \code{object[["RNA"]]}) } \examples{ cluster_letters <- LETTERS[Idents(object = pbmc_small)] names(cluster_letters) <- colnames(x = pbmc_small) pbmc_small <- AddMetaData( object = pbmc_small, metadata = cluster_letters, col.name = 'letter.idents' ) head(x = pbmc_small[[]]) } \concept{seurat} SeuratObject/man/Crop.Rd0000644000176200001440000000154114520004201014576 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/fov.R \name{Crop} \alias{Crop} \alias{Crop.FOV} \title{Crop Coordinates} \usage{ Crop(object, x = NULL, y = NULL, coords = c("plot", "tissue"), ...) \method{Crop}{FOV}(object, x = NULL, y = NULL, coords = c("plot", "tissue"), ...) } \arguments{ \item{object}{An object} \item{x, y}{Range to crop x/y limits to; if \code{NULL}, uses full range of \code{x}/\code{y}} \item{coords}{Coordinate system to execute crop; choose from: \itemize{ \item \dQuote{\code{plot}}: Coordinates as shown when plotting \item \dQuote{\code{tissue}}: Coordinates from \code{\link{GetTissueCoordinates}} }} \item{...}{Arguments passed to other methods} } \value{ \code{object} cropped to the region specified by \code{x} and \code{y} } \description{ Crop Coordinates } \concept{spatial} SeuratObject/man/show-Seurat-method.Rd0000644000176200001440000000064514520004144017404 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/seurat.R \name{show,Seurat-method} \alias{show,Seurat-method} \title{Seurat Object Overview} \usage{ \S4method{show}{Seurat}(object) } \value{ Prints summary to \code{\link[base]{stdout}} and invisibly returns \code{NULL} } \description{ Overview of a \code{\link{Seurat}} object } \examples{ pbmc_small } \concept{seurat} \keyword{internal} SeuratObject/man/dot-RandomKey.Rd0000644000176200001440000000106014520004144016352 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/keymixin.R \name{.RandomKey} \alias{.RandomKey} \title{Generate a Random Key} \usage{ .RandomKey(length = 7L, ...) } \arguments{ \item{length}{How long should the name be} \item{...}{Extra parameters passed to \code{\link[base]{sample}}} } \value{ Returns a valid key } \description{ Generate a Random Key } \examples{ set.seed(42L) .RandomKey() } \seealso{ \code{\link{.KeyPattern}()}, \code{\link{Key-validity}}, \code{\link{KeyMixin-class}} } \concept{key} \keyword{internal} SeuratObject/man/sub-sub-LogMap-internal-method.Rd0000644000176200001440000000124014520004144021522 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/logmap.R \name{[[,LogMap,integer,missing-method} \alias{[[,LogMap,integer,missing-method} \alias{[[,LogMap,numeric,missing-method} \title{\code{\link{LogMap}} Interaction Methods} \usage{ \S4method{[[}{LogMap,integer,missing}(x, i, j, ...) \S4method{[[}{LogMap,numeric,missing}(x, i, j, ...) } \arguments{ \item{x}{A \code{LogMap} object} \item{i}{An integer or numeric vector of length 1} \item{j}{Not used} \item{...}{Ignored} } \value{ The rownames that are mapped to \code{i} } \description{ Additional methods for using \code{[[} with \code{\link{LogMap}} objects } \keyword{internal} SeuratObject/man/oldseurat-class.Rd0000644000176200001440000000475214520004144017015 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/seurat.R \docType{class} \name{seurat-class} \alias{seurat-class} \alias{oldseurat} \title{The Seurat Class} \description{ The Seurat object is the center of each single cell analysis. It stores all information associated with the dataset, including data, annotations, analyses, etc. All that is needed to construct a Seurat object is an expression matrix (rows are genes, columns are cells), which should be log-scale } \details{ Each Seurat object has a number of slots which store information. Key slots to access are listed below. } \section{Slots}{ \describe{ \item{\code{raw.data}}{The raw project data} \item{\code{data}}{The normalized expression matrix (log-scale)} \item{\code{scale.data}}{scaled (default is z-scoring each gene) expression matrix; used for dimensional reduction and heatmap visualization} \item{\code{var.genes}}{Vector of genes exhibiting high variance across single cells} \item{\code{is.expr}}{Expression threshold to determine if a gene is expressed (0 by default)} \item{\code{ident}}{THe 'identity class' for each cell} \item{\code{meta.data}}{Contains meta-information about each cell, starting with number of genes detected (nFeature) and the original identity class (orig.ident); more information is added using \code{AddMetaData}} \item{\code{project.name}}{Name of the project (for record keeping)} \item{\code{dr}}{List of stored dimensional reductions; named by technique} \item{\code{assay}}{List of additional assays for multimodal analysis; named by technique} \item{\code{hvg.info}}{The output of the mean/variability analysis for all genes} \item{\code{imputed}}{Matrix of imputed gene scores} \item{\code{cell.names}}{Names of all single cells (column names of the expression matrix)} \item{\code{cluster.tree}}{List where the first element is a phylo object containing the phylogenetic tree relating different identity classes} \item{\code{snn}}{Spare matrix object representation of the SNN graph} \item{\code{calc.params}}{Named list to store all calculation-related parameter choices} \item{\code{kmeans}}{Stores output of gene-based clustering from \code{DoKMeans}} \item{\code{spatial}}{Stores internal data and calculations for spatial mapping of single cells} \item{\code{misc}}{Miscellaneous spot to store any data alongside the object (for example, gene lists)} \item{\code{version}}{Version of package used in object creation} }} \concept{unsorted} \concept{v2} \keyword{internal} SeuratObject/man/Boundaries.Rd0000644000176200001440000000231714520004144015776 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/fov.R \name{Boundaries} \alias{Boundaries} \alias{DefaultBoundary} \alias{DefaultBoundary<-} \alias{Molecules} \alias{Boundaries.FOV} \alias{DefaultBoundary.FOV} \alias{DefaultBoundary<-.FOV} \alias{Molecules.FOV} \title{Get, Set, and Query Segmentation Boundaries} \usage{ Boundaries(object, ...) DefaultBoundary(object) DefaultBoundary(object, ...) <- value Molecules(object, ...) \method{Boundaries}{FOV}(object, ...) \method{DefaultBoundary}{FOV}(object) \method{DefaultBoundary}{FOV}(object, ...) <- value \method{Molecules}{FOV}(object, ...) } \arguments{ \item{object}{An object} \item{...}{Arguments passed to other methods} \item{value}{The name of a segmentation boundary to set as default} } \value{ \code{Boundaries}: The names of all segmentation boundaries present within \code{object} \code{DefaultBoundary}: The name of the default segmentation boundary \code{DefaultBoundary<-}: \code{object} with the default segmentation boundary set to \code{value} \code{Molecules}: The names of all molecule sets present within \code{object} } \description{ Get, Set, and Query Segmentation Boundaries } \concept{spatial} SeuratObject/man/CreateSegmentation.Rd0000644000176200001440000000131514520004201017453 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/segmentation.R \name{CreateSegmentation} \alias{CreateSegmentation} \alias{CreateSegmentation.data.frame} \alias{CreateSegmentation.Segmentation} \title{Create a \code{\link[SeuratObject:Segmentation-class]{Segmentation}} Objects} \usage{ CreateSegmentation(coords) \method{CreateSegmentation}{data.frame}(coords) \method{CreateSegmentation}{Segmentation}(coords) } \arguments{ \item{coords}{The coordinates of cell segmentations} } \value{ A \code{\link[SeuratObject:Segmentation-class]{Segmentation}} object } \description{ Create a \code{\link[SeuratObject:Segmentation-class]{Segmentation}} Objects } \concept{spatial} SeuratObject/man/CreateAssay5Object.Rd0000644000176200001440000000202114520004144017313 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay5.R \name{CreateAssay5Object} \alias{CreateAssay5Object} \title{Create a v5 Assay object} \usage{ CreateAssay5Object( counts = NULL, data = NULL, min.cells = 0, min.features = 0, csum = NULL, fsum = NULL, ... ) } \arguments{ \item{counts}{A two-dimensional expression matrix} \item{data}{Optional prenormalized data matrix} \item{min.cells}{Include features detected in at least this many cells; will subset the counts matrix as well. To reintroduce excluded features, create a new object with a lower cutoff} \item{min.features}{Include cells where at least this many features are detected} \item{csum}{Function for calculating cell sums} \item{fsum}{Function for calculating feature sums} \item{...}{Arguments passed to other methods} } \value{ An \code{\link{Assay5}} object } \description{ Create an \code{\link{Assay5}} object from a feature expression matrix; the expected format of the matrix is features x cells } \concept{assay} SeuratObject/man/sub-sub-.DimReduc.Rd0000644000176200001440000000210414520004144017025 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/dimreduc.R \name{[[.DimReduc} \alias{[[.DimReduc} \title{Get Cell Embeddings} \usage{ \method{[[}{DimReduc}(x, i, j, drop = FALSE, ...) } \arguments{ \item{x}{A \code{\link{DimReduc}} object} \item{i}{Cell names or indices} \item{j}{Dimension identifiers or indices} \item{drop}{Coerce the result to the lowest possible dimension; see \code{\link{drop}} for further details} \item{...}{Arguments passed to other methods} } \value{ Cell embeddings for cells \code{i} and dimensions \code{j} } \description{ Pull cell embeddings from a \link[=DimReduc]{dimensional reduction} } \examples{ pca <- pbmc_small[["pca"]] pca[[1:10, 1:5]] } \seealso{ \code{\link{Embeddings}} Dimensional reduction object, validity, and interaction methods \code{\link{CreateDimReducObject}()}, \code{\link{DimReduc-class}}, \code{\link{DimReduc-validity}}, \code{\link{[.DimReduc}()}, \code{\link{dim.DimReduc}()}, \code{\link{merge.DimReduc}()}, \code{\link{print.DimReduc}()}, \code{\link{subset.DimReduc}()} } \concept{dimreduc} SeuratObject/man/Neighbor-methods.Rd0000644000176200001440000000142014473173564017117 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/neighbor.R \name{Neighbor-methods} \alias{Neighbor-methods} \alias{dim.Neighbor} \alias{show,Neighbor-method} \title{\code{Neighbor} Methods} \usage{ \method{dim}{Neighbor}(x) \S4method{show}{Neighbor}(object) } \arguments{ \item{x, object}{A \code{\link{Neighbor}} object} } \value{ \code{dim} Dimensions of the indices matrix \code{show}: Prints summary to \code{\link[base]{stdout}} and invisibly returns \code{NULL} } \description{ Methods for \code{\link{Neighbor}} objects for generics defined in other packages } \section{Functions}{ \itemize{ \item \code{dim(Neighbor)}: Dimensions of the neighbor indices \item \code{show(Neighbor)}: Overview of a \code{Neighbor} object }} \concept{neighbor} SeuratObject/man/LogMap-validity.Rd0000644000176200001440000000206514520004144016705 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/logmap.R \name{LogMap-validity} \alias{LogMap-validity} \title{Logical Map Validity} \description{ Validation of \code{LogMap} objects is handled by \code{\link[methods]{validObject}} } \section{Data Validation}{ Logical maps must be a logical matrix containing only TRUE or FALSE values } \section{Value Validation}{ All values must be named within the rownames of the object. Duplicate or empty (\code{""}) values are not allowed } \section{Observation Validation}{ All observations must be named within the column names of the object. Duplicate or empty (\code{""}) observations are not allowed } \examples{ map <- LogMap(letters[1:10]) map[['obs']] <- c(1, 3, 7) map[['entry']] <- c(2, 7, 10) validObject(map) } \seealso{ \code{\link[methods]{validObject}} Logical map objects, validity, and interaction methods: \code{\link{LogMap}}, \code{\link{as.matrix.LogMap}()}, \code{\link{droplevels.LogMap}()}, \code{\link{intersect.LogMap}()}, \code{\link{labels.LogMap}()} } \concept{logmap} SeuratObject/man/show-oldseurat-method.Rd0000644000176200001440000000073214520004144020140 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/seurat.R \name{show,seurat-method} \alias{show,seurat-method} \title{Old Seurat Object Overview} \usage{ \S4method{show}{seurat}(object) } \arguments{ \item{object}{An old seurat object} } \value{ Prints summary to \code{\link[base]{stdout}} and invisibly returns \code{NULL} } \description{ Overview of a \code{\link[=oldseurat]{seurat}} object overview } \concept{oldseurat} \keyword{internal} SeuratObject/man/CastAssay.Rd0000644000176200001440000000140514520004201015565 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/assay5.R \name{CastAssay} \alias{CastAssay} \alias{CastAssay.Assay5} \title{Cast Assay Layers} \usage{ CastAssay(object, to, ...) \method{CastAssay}{Assay5}(object, to, layers = NA, verbose = TRUE, ...) } \arguments{ \item{object}{An object} \item{to}{Either a class name or a function that takes a layer and returns the same layer as a new class} \item{...}{If \code{to} is a function, arguments passed to \code{to}} \item{layers}{A vector of layers to cast; defaults to all layers} \item{verbose}{Show progress updates} } \value{ \code{object} with the layers cast to class specified by \code{to} } \description{ Cast layers in v5 assays to other classes } \concept{assay5} SeuratObject/man/dot-GetMethod.Rd0000644000176200001440000000110414520004144016340 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{.GetMethod} \alias{.GetMethod} \title{Get a Method} \usage{ .GetMethod(fxn, cls) } \arguments{ \item{fxn}{Name of a function as a character} \item{cls}{The class to find a method of \code{fxn} for} } \value{ The method of \code{fxn} for class \code{cls}; if no method found, returns the default method. If no default method found; returns \code{NULL} } \description{ Get a Method } \examples{ .GetMethod('t', 'Matrix') .GetMethod('t', 'data.frame') } \concept{utils} \keyword{internal} SeuratObject/man/show-Graph-method.Rd0000644000176200001440000000065314520004144017201 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/graph.R \name{show,Graph-method} \alias{show,Graph-method} \title{Graph Object Overview} \usage{ \S4method{show}{Graph}(object) } \value{ Prints summary to \code{\link[base]{stdout}} and invisibly returns \code{NULL} } \description{ Overview of a \code{\link{Graph}} Object } \examples{ pbmc_small[["RNA_snn"]] } \concept{graph} \keyword{internal} SeuratObject/man/ExtractField.Rd0000644000176200001440000000136414520004144016262 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{ExtractField} \alias{ExtractField} \title{Extract delimiter information from a string.} \usage{ ExtractField(string, field = 1, delim = "_") } \arguments{ \item{string}{String to parse.} \item{field}{Integer(s) indicating which field(s) to extract. Can be a vector multiple numbers.} \item{delim}{Delimiter to use, set to underscore by default.} } \value{ A new string, that parses out the requested fields, and (if multiple), rejoins them with the same delimiter } \description{ Parses a string (usually a cell name) and extracts fields based on a delimiter } \examples{ ExtractField('Hello World', field = 1, delim = '_') } \concept{utils} \keyword{internal} SeuratObject/man/colMeans-Assay-method.Rd0000644000176200001440000000270614520004144020002 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay.R \name{colMeans,Assay-method} \alias{colMeans,Assay-method} \alias{colSums,Assay-method} \alias{rowMeans,Assay-method} \alias{rowSums,Assay-method} \title{Row and Column Sums and Means} \usage{ \S4method{colMeans}{Assay}(x, na.rm = FALSE, dims = 1, ..., slot = "data") \S4method{colSums}{Assay}(x, na.rm = FALSE, dims = 1, ..., slot = "data") \S4method{rowMeans}{Assay}(x, na.rm = FALSE, dims = 1, ..., slot = "data") \S4method{rowSums}{Assay}(x, na.rm = FALSE, dims = 1, ..., slot = "data") } \arguments{ \item{x}{An \code{\link{Assay}} object} \item{na.rm}{logical. Should missing values (including \code{NaN}) be omitted from the calculations?} \item{dims}{completely ignored by the \code{Matrix} methods.} \item{...}{Ignored} \item{slot}{Name of assay expression matrix to calculate column/row means/sums on} } \value{ \code{colMeans}: The column (cell-wise) means of \code{slot} \code{colSums}: The column (cell-wise) sums of \code{slot} \code{rowMeans}: The row (feature-wise) means of \code{slot} \code{rowSums}: The row (feature-wise) sums of \code{slot} } \description{ Calculate \code{\link{rowSums}}, \code{\link{colSums}}, \code{\link{rowMeans}}, and \code{\link{colMeans}} on \code{Assay} objects } \examples{ rna <- pbmc_small[["RNA"]] colMeans(rna) colSums(rna) rowMeans(rna) rowSums(rna) } \seealso{ \code{\link{Assay}} } \concept{assay} \keyword{internal} SeuratObject/man/IsGlobal.Rd0000644000176200001440000000163214473173564015422 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/default.R, R/dimreduc.R \name{IsGlobal} \alias{IsGlobal} \alias{IsGlobal.default} \alias{IsGlobal.DimReduc} \title{Is an object global/persistent?} \usage{ IsGlobal(object, ...) \method{IsGlobal}{default}(object, ...) \method{IsGlobal}{DimReduc}(object, ...) } \arguments{ \item{object}{An object} \item{...}{Arguments passed to other methods} } \value{ \code{TRUE} if the object is global/persistent otherwise \code{FALSE} } \description{ Typically, when removing \code{Assay} objects from an \code{Seurat} object, all associated objects (eg. \code{DimReduc}, \code{Graph}, and \code{SeuratCommand} objects) are removed as well. If an associated object is marked as global/persistent, the associated object will remain even if its original assay was deleted } \examples{ IsGlobal(pbmc_small[['pca']]) } \concept{data-access} SeuratObject/man/RenameCells-StdAssay.Rd0000644000176200001440000000134314520004144017624 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay5.R \name{RenameCells-StdAssay} \alias{RenameCells-StdAssay} \alias{RenameCells.StdAssay} \title{Rename cells} \usage{ \method{RenameCells}{StdAssay}(object, new.names = NULL, ...) } \arguments{ \item{object}{An object} \item{new.names}{vector of new cell names} \item{...}{Arguments passed to other methods} } \value{ An object with new cell names } \description{ Change the cell names in all the different parts of an object. Can be useful before combining multiple objects. } \details{ If \code{add.cell.id} is set a prefix is added to existing cell names. If \code{new.names} is set these will be used to replace existing names. } \keyword{internal} SeuratObject/man/dot-FileMove.Rd0000644000176200001440000000176214520004144016200 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{.FileMove} \alias{.FileMove} \title{Move Files and Directories} \usage{ .FileMove(path, new_path, overwrite = FALSE, n = 1L) } \arguments{ \item{path}{A character vector of one or more paths.} \item{new_path}{New file path. If \code{new_path} is existing directory, the file will be moved into that directory; otherwise it will be moved/renamed to the full path. Should either be the same length as \code{path}, or a single directory.} \item{n}{The number of callers to go back.} } \value{ The new path (invisibly). } \description{ Move files and directories with \pkg{fs}; includes a handler for when \code{path} is a directory on a different filesystem than \code{new_path} by explicitly copying and deleting \code{path} } \note{ This function requires the \href{https://cran.r-project.org/package=fs}{\pkg{fs}} package to be installed } \seealso{ \code{\link[fs:file_move]{fs::file_move}()} } \keyword{internal} SeuratObject/man/Layers.Rd0000644000176200001440000000513614520004144015144 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/assay.R, R/assay5.R, R/seurat.R \name{LayerData} \alias{LayerData} \alias{LayerData<-} \alias{Layers} \alias{LayerData.Assay} \alias{LayerData<-.Assay} \alias{Layers.Assay} \alias{LayerData.Assay5} \alias{LayerData<-.Assay5} \alias{Layers.Assay5} \alias{LayerData.Seurat} \alias{LayerData<-.Seurat} \alias{Layers.Seurat} \title{Query and Manipulate Assay Layers} \usage{ LayerData(object, layer, ...) LayerData(object, layer, ...) <- value Layers(object, ...) \method{LayerData}{Assay}( object, layer = NULL, cells = NULL, features = NULL, slot = deprecated(), ... ) \method{LayerData}{Assay}(object, layer, ...) <- value \method{Layers}{Assay}(object, search = NA, ...) \method{LayerData}{Assay5}( object, layer = NULL, cells = NULL, features = NULL, fast = FALSE, slot = deprecated(), ... ) \method{LayerData}{Assay5}(object, layer, features = NULL, cells = NULL, ...) <- value \method{Layers}{Assay5}(object, search = NA, ...) \method{LayerData}{Seurat}(object, layer = NULL, assay = NULL, slot = deprecated(), ...) \method{LayerData}{Seurat}(object, layer, assay = NULL, ...) <- value \method{Layers}{Seurat}(object, search = NA, assay = NULL, ...) } \arguments{ \item{object}{An object} \item{layer}{Name of layer to fetch or set} \item{...}{Arguments passed to other methods} \item{value}{New two-dimensional data to be added as a layer} \item{features, cells}{Vectors of features/cells to include} \item{slot}{\Sexpr[stage=build,results=rd]{lifecycle::badge("deprecated")}} \item{search}{A pattern to search layer names for; pass one of: \itemize{ \item \dQuote{\code{NA}} to pull all layers \item \dQuote{\code{NULL}} to pull the default layer(s) \item a \link[base:grep]{regular expression} that matches layer names }} \item{fast}{Determine how to return the layer data; choose from: \describe{ \item{\code{FALSE}}{Apply any transpositions and attempt to add feature/cell names (if supported) back to the layer data} \item{\code{NA}}{Attempt to add feature/cell names back to the layer data, skip any transpositions} \item{\code{TRUE}}{Do not apply any transpositions or add feature/cell names to the layer data} }} \item{assay}{Name of assay to fetch layer data from or assign layer data to} } \value{ \code{LayerData}: the layer data for \code{layer} from \code{object} \code{Layer<-}: \code{object} with \code{value} added as a layer named \code{layer} \code{Layers}: the names of the layers present in \code{object} } \description{ Query and Manipulate Assay Layers } \concept{data-access} SeuratObject/man/sub-subset-Seurat-NULL.Rd0000644000176200001440000000240314520004144020004 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/seurat.R \name{[[<-,Seurat,NULL} \alias{[[<-,Seurat,NULL} \alias{remove-object} \alias{remove-objects} \alias{\S4method{[[<-}{Seurat,character,missing,NULL}} \alias{[[<-,Seurat,character,missing,NULL-method} \title{Remove Subobjects and Cell-Level Meta Data} \usage{ \S4method{[[}{Seurat,character,missing,`NULL`}(x, i, j, ...) <- value } \arguments{ \item{x}{A \code{\link{Seurat}} object} \item{i}{Name(s) of subobject(s) or cell-level meta data to remove} \item{j}{Ignored} \item{...}{Ignored} \item{value}{NULL} } \value{ \code{x} with \code{i} removed from the object } \description{ Remove Subobjects and Cell-Level Meta Data } \seealso{ See \link[=[[.Seurat]{here} for pulling subobjects using \code{[[}, \link[=$.Seurat]{here} for adding metadata with \code{[[<-}, and \link[=[[<-,Seurat]{here} for adding subobjects with \code{[[<-} Seurat object, validity, and interaction methods \code{\link{$.Seurat}()}, \code{\link{Seurat-class}}, \code{\link{Seurat-validity}}, \code{\link{[[.Seurat}()}, \code{\link{[[<-,Seurat}}, \code{\link{dim.Seurat}()}, \code{\link{dimnames.Seurat}()}, \code{\link{merge.Seurat}()}, \code{\link{names.Seurat}()}, \code{\link{subset.Seurat}()} } \concept{seurat} SeuratObject/man/RegisterSparseMatrix.Rd0000644000176200001440000000112714520004144020030 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/sparse.R \name{RegisterSparseMatrix} \alias{RegisterSparseMatrix} \title{Register Sparse Matrix Classes} \usage{ RegisterSparseMatrix(class, package = NULL) } \arguments{ \item{class}{Class name} \item{package}{Optional name of package; by default, will search namespaces of loaded packages to determine the providing package} } \value{ Invisibly returns \code{NULL} } \description{ Register Sparse Matrix Classes } \seealso{ \code{\link{.SparseSlots}()}, \code{\link{IsSparse}()} } \concept{sparse} \keyword{internal} SeuratObject/man/as.Graph.Rd0000644000176200001440000000225414520004144015346 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/graph.R \name{as.Graph} \alias{as.Graph} \alias{as.Graph.Matrix} \alias{as.Graph.matrix} \alias{as.Graph.Neighbor} \title{Coerce to a \code{Graph} Object} \usage{ as.Graph(x, ...) \method{as.Graph}{Matrix}(x, ...) \method{as.Graph}{matrix}(x, ...) \method{as.Graph}{Neighbor}(x, weighted = TRUE, ...) } \arguments{ \item{x}{The matrix to convert} \item{...}{Ignored} \item{weighted}{If TRUE, fill entries in Graph matrix with value from the nn.dist slot of the Neighbor object} } \value{ A \code{\link{Graph}} object } \description{ Convert a \code{\link[base]{matrix}} (or \code{\link[Matrix]{Matrix}}) to a \code{\link{Graph}} object } \examples{ # converting sparse matrix mat <- Matrix::rsparsematrix(nrow = 10, ncol = 10, density = 0.1) rownames(x = mat) <- paste0("feature_", 1:10) colnames(x = mat) <- paste0("cell_", 1:10) g <- as.Graph(x = mat) # converting dense matrix mat <- matrix(data = 1:16, nrow = 4) rownames(x = mat) <- paste0("feature_", 1:4) colnames(x = mat) <- paste0("cell_", 1:4) g <- as.Graph(x = mat) } \seealso{ Other graph: \code{\link{Graph-class}} } \concept{graph} SeuratObject/man/dim.DimReduc.Rd0000644000176200001440000000313514520004144016146 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/dimreduc.R \name{dim.DimReduc} \alias{dim.DimReduc} \alias{dimnames.DimReduc} \alias{length.DimReduc} \alias{names.DimReduc} \title{Dimensional Reduction Meta-Information} \usage{ \method{dim}{DimReduc}(x) \method{dimnames}{DimReduc}(x) \method{length}{DimReduc}(x) \method{names}{DimReduc}(x) } \arguments{ \item{x}{A \code{\link{DimReduc}} object} } \value{ \code{dim}: The number of cells (\code{nrow}) and dimensions (\code{ncol}) \code{dimnames}: The cell (row) and dimension (column) names \code{length}: The number of dimensions \code{names}: The dimension identifiers } \description{ Pull meta-information about cells and dimensions for a given \link[=DimReduc]{dimensional reduction}; cell meta-information is stored as row meta-information (eg. \code{nrow}, \code{rownames}) and dimension meta-information is stored as column meta-information (eg. \code{ncol}, \code{colnames}) } \examples{ pca <- pbmc_small[["pca"]] pca dim(pca) # nrow is number of cells nrow(pca) # rownames pulls cell names head(rownames(pca)) # ncol and length are number of dimensions ncol(pca) length(pca) # colnames and names pull dimension identifiers head(colnames(pca)) head(names(pca)) } \seealso{ \code{Cells} Dimensional reduction object, validity, and interaction methods \code{\link{CreateDimReducObject}()}, \code{\link{DimReduc-class}}, \code{\link{DimReduc-validity}}, \code{\link{[.DimReduc}()}, \code{\link{[[.DimReduc}()}, \code{\link{merge.DimReduc}()}, \code{\link{print.DimReduc}()}, \code{\link{subset.DimReduc}()} } \concept{dimreduc} SeuratObject/man/v5-assay-summaries.Rd0000644000176200001440000000265114520004144017357 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay5.R \name{v5-assay-summaries} \alias{v5-assay-summaries} \alias{colMeans,StdAssay-method} \alias{colSums,StdAssay-method} \alias{rowMeans,StdAssay-method} \alias{rowSums,StdAssay-method} \title{V5 Assay Summaries} \usage{ \S4method{colMeans}{StdAssay}(x, na.rm = FALSE, dims = 1, layer = NULL, ...) \S4method{colSums}{StdAssay}(x, na.rm = FALSE, dims = 1, layer = NULL, ...) \S4method{rowMeans}{StdAssay}(x, na.rm = FALSE, dims = 1, layer = NULL, ...) \S4method{rowSums}{StdAssay}(x, na.rm = FALSE, dims = 1, layer = NULL, ...) } \arguments{ \item{x}{an array of two or more dimensions, containing numeric, complex, integer or logical values, or a numeric data frame. For \code{.colSums()} etc, a numeric, integer or logical matrix (or vector of length \code{m * n}).} \item{na.rm}{logical. Should missing values (including \code{NaN}) be omitted from the calculations?} \item{dims}{integer: Which dimensions are regarded as \sQuote{rows} or \sQuote{columns} to sum over. For \code{row*}, the sum or mean is over dimensions \code{dims+1, \dots}; for \code{col*} it is over dimensions \code{1:dims}.} \item{layer}{Name of layer to run function on} \item{...}{Ignored} } \value{ The results of the summary math function for the layer specified } \description{ Summary maths for \code{\link{StdAssay}} Objects } \keyword{internal} SeuratObject/man/roxygen/0000755000176200001440000000000014520004144015104 5ustar liggesusersSeuratObject/man/roxygen/templates/0000755000176200001440000000000014520004144017102 5ustar liggesusersSeuratObject/man/roxygen/templates/section-progressr.R0000644000176200001440000000104714473173564022743 0ustar liggesusers#' @section Progress Updates with \pkg{progressr}: #' This function uses #' \href{https://cran.r-project.org/package=progressr}{\pkg{progressr}} to #' render status updates and progress bars. To enable progress updates, wrap #' the function call in \code{\link[progressr]{with_progress}} or run #' \code{\link[progressr:handlers]{handlers(global = TRUE)}} before running #' this function. For more details about \pkg{progressr}, please read #' \href{https://progressr.futureverse.org/articles/progressr-intro.html}{\code{vignette("progressr-intro")}} SeuratObject/man/roxygen/templates/method-lengths.R0000644000176200001440000000030114473173564022165 0ustar liggesusers#' @param use.names Ignored #' #' @details \code{lengths}: Generate a run-length encoding of the cells present #' #' @return \code{lengths}: An \code{\link[base:rle]{rle}} object for the cells SeuratObject/man/roxygen/templates/method-show.R0000644000176200001440000000016614513654541021504 0ustar liggesusers#' @details \code{show}: Display an object summary to stdout #' #' @return \code{show}: Invisibly returns \code{NULL} SeuratObject/man/roxygen/templates/slot-key.R0000644000176200001440000000037214520004144020776 0ustar liggesusers#' @slot key A one-length character vector with the object's key; keys must #' be one or more alphanumeric characters followed by an underscore #' \dQuote{\code{_}} (regex pattern #' \dQuote{\code{\Sexpr[stage=build]{SeuratObject:::.KeyPattern()}}}) SeuratObject/man/roxygen/templates/seealso-methods.R0000644000176200001440000000011014473173564022335 0ustar liggesusers#' @seealso \code{<%= cls %>} methods: \code{\link{<%= cls %>-methods}} SeuratObject/man/roxygen/templates/lifecycle-superseded.R0000644000176200001440000000013414520004144023323 0ustar liggesusers#' @section Lifecycle: #' #' \Sexpr[stage=build,results=rd]{lifecycle::badge("superseded")} SeuratObject/man/roxygen/templates/param-verbose.R0000644000176200001440000000005014520004144021763 0ustar liggesusers#' @param verbose Show progress updates SeuratObject/man/roxygen/templates/desc-validity.R0000644000176200001440000000015414520004144021766 0ustar liggesusers#' @description Validation of \code{<%= cls %>} objects is handled by #' \code{\link[methods]{validObject}} SeuratObject/man/roxygen/templates/param-dots-method.R0000644000176200001440000000006014520004144022546 0ustar liggesusers#' @param ... Arguments passed to other methods SeuratObject/man/roxygen/templates/param-dots-ignored.R0000644000176200001440000000002614520004144022717 0ustar liggesusers#' @param ... Ignored SeuratObject/man/roxygen/templates/method-features.R0000644000176200001440000000031514473173564022344 0ustar liggesusers#' @details \code{Features}: Get spatially-resolved molecule names #' #' @return \code{Features}: A vector of spatially-resolved molecule names; #' if no molecular information present, returns \code{NULL} SeuratObject/man/roxygen/templates/method-stdassay.R0000644000176200001440000000030714520004144022336 0ustar liggesusers#' @inherit <%= fxn %> params return title description details sections #' references author source #' @name <%= fxn %>-StdAssay #' @rdname <%= fxn %>-StdAssay #' #' @keywords internal #' #' @export SeuratObject/man/roxygen/templates/note-reqdpkg.R0000644000176200001440000000021114473173564021643 0ustar liggesusers#' @note This function requires the #' \href{https://cran.r-project.org/package=<%= pkg %>}{\pkg{<%= pkg %>}} package #' to be installed SeuratObject/man/roxygen/templates/lifecycle-deprecated.R0000644000176200001440000000043614520004144023265 0ustar liggesusers#' @section Lifecycle: #' #' \Sexpr[stage=build,results=rd]{lifecycle::badge("deprecated")} #' #' \code{<%= fxn %>} <%= if (exists("ver")) paste("was deprecated in version", ver) else "has been deprecated" %><%= if (exists("repl")) paste0("; use \\code{\\link{", repl, "}} instead") %> SeuratObject/man/roxygen/templates/slot-stdassay.R0000644000176200001440000000230714520004144022041 0ustar liggesusers#' @slot layers A named list containing expression matrices; each matrix should #' be a two-dimensional object containing some subset of cells and features #' defined in the \code{cells} and \code{features} slots. Cell and feature #' membership is recorded in the \code{cells} and \code{features} slots, #' respectively #' @slot cells A \link[=LogMap]{logical mapping} of cell names #' and layer membership; this map contains all the possible cells that this #' assay can contain. New layers must have some subset of cells present #' in this map #' @slot features A \link[=LogMap]{logical mapping} of feature #' names and layer membership; this map contains all the possible features that #' this assay can contain. New layers must have some subset of features #' present in this map #' @slot default A one-length integer with the end index of the #' \link[=DefaultLayer]{default layer}; the default layer be #' all layers up to and including the layer at index \code{default} #' @slot assay.orig Original assay that this assay is based off of; #' used to track assay provenance #' @slot meta.data A \link[base:data.frame]{data frame} with feature-level #' meta data; should have the same number of rows as \code{features} SeuratObject/man/roxygen/templates/method-cells.R0000644000176200001440000000013414473173564021627 0ustar liggesusers#' @details \code{Cells}: Get cell names #' #' @return \code{Cells}: A vector of cell names SeuratObject/man/roxygen/templates/return-show.R0000644000176200001440000000013514520004144021521 0ustar liggesusers#' @return Prints summary to \code{\link[base]{stdout}} and invisibly #' returns \code{NULL} SeuratObject/man/roxygen/templates/lifecycle-experimental.R0000644000176200001440000000031114520004144023652 0ustar liggesusers#' @section Lifecycle: #' #' \Sexpr[stage=build,results=rd]{lifecycle::badge("experimental")} #' #' \strong{Warning}: functionality described here is experimental and prone to #' change without notice SeuratObject/man/roxygen/templates/slot-misc.R0000644000176200001440000000007614520004144021142 0ustar liggesusers#' @slot misc A named list of unstructured miscellaneous data SeuratObject/man/roxygen/templates/section-future.R0000644000176200001440000000132714473173564022230 0ustar liggesusers#' @section Parallelization with \pkg{future}: #' This function uses #' \href{https://cran.r-project.org/package=future}{\pkg{future}} to enable #' parallelization. Parallelization strategies can be set using #' \code{\link[future]{plan}}. Common plans include \dQuote{\code{sequential}} #' for non-parallelized processing or \dQuote{\code{multisession}} for parallel #' evaluation using multiple \R sessions; for other plans, see the #' \dQuote{Implemented evaluation strategies} section of #' \code{\link[future:plan]{?future::plan}}. For a more thorough introduction #' to \pkg{future}, see #' \href{https://future.futureverse.org/articles/future-1-overview.html}{\code{vignette("future-1-overview")}} #' #' @concept future SeuratObject/man/roxygen/templates/return-null.R0000644000176200001440000000005114520004144021510 0ustar liggesusers#' @return Invisibly returns \code{NULL} SeuratObject/man/roxygen/templates/name-oldv.R0000644000176200001440000000047114520004144021111 0ustar liggesusers#' @name <%= fname %>-v<%= as.integer(version) %> #' @rdname <%= fname %>-v<%= as.integer(version) %> #' #' @note This is the documentation for \code{<%= fname %>} for #' v<%= as.integer(version) %>; for the latest documentation, please see #' \code{\link{<%= fname %>}} #' #' @seealso \code{\link{<%= fname %>}} SeuratObject/man/roxygen/meta.R0000644000176200001440000000127214520004144016157 0ustar liggesuserslist( rd_family_title = list( angles = "", assay = "v3 Assay object, validity, and interaction methods:", assay5 = "v5 Assay object, validity, and interaction methods:", command = "Command log object and interaction methods", dimnames = "", dimreduc = "Dimensional reduction object, validity, and interaction methods", fov = "", key = "", logmap = "Logical map objects, validity, and interaction methods:", s4list = "", segmentation = "Segmentation layer classes:", seurat = "Seurat object, validity, and interaction methods", sparse = "", stdassay = "v5 Standard Assay object, validity, and interaction methods", subobjects = "" ) ) SeuratObject/man/Centroids-class.Rd0000644000176200001440000000217314520004201016732 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/centroids.R \docType{class} \name{Centroids-class} \alias{Centroids-class} \title{The \code{Centroids} Class} \description{ The \code{Centroids} Class } \section{Slots}{ \describe{ \item{\code{cells}}{(\code{\link[base:character]{character [n]}}) A vector of cell names; there should be as many cell names as there are points and no duplicate names} \item{\code{nsides}}{(\code{\link[base:integer]{integer [1L]}}) The number of sides to draw when plotting centroids; must be either \code{0L} for circles or greater than 3} \item{\code{radius}}{(\code{\link[base:numeric]{numeric [1L]}}) The radius of the shape when plotting the centroids} \item{\code{theta}}{(\code{\link[base:numeric]{numeric [1L]}}) The angle in degrees to adjust the shape when plotting the centroids} }} \seealso{ \code{Centroids} methods: \code{\link{Centroids-methods}} Segmentation layer classes: \code{\link{Centroids-methods}}, \code{\link{Molecules-class}}, \code{\link{Molecules-methods}}, \code{\link{Segmentation-class}}, \code{\link{Segmentation-methods}} } \concept{segmentation} SeuratObject/man/sub-.Assay5.Rd0000644000176200001440000000207514520004144015716 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay5.R \name{[.Assay5} \alias{[.Assay5} \alias{[<-,Assay5,character,ANY,ANY-method} \title{Layer Data} \usage{ \method{[}{Assay5}(x, i = missing_arg(), j = missing_arg(), ...) \S4method{[}{Assay5,character,ANY,ANY}(x, i, j, ...) <- value } \arguments{ \item{x}{An \code{\link{Assay5}} object} \item{i}{Name of layer data to get or set} \item{j}{Ignored} \item{...}{Arguments passed to \code{\link{LayerData}}} \item{value}{A matrix-like object to add as a new layer} } \value{ \code{[}: The layer data for layer \code{i} \code{[<-}: \code{x} with layer data \code{value} saved as \code{i} } \description{ Get and set layer data } \seealso{ \code{\link{LayerData}} v5 Assay object, validity, and interaction methods: \code{\link{$.Assay5}()}, \code{\link{Assay5-class}}, \code{\link{Assay5-validity}}, \code{\link{[[.Assay5}()}, \code{\link{dim.Assay5}()}, \code{\link{dimnames.Assay5}()}, \code{\link{merge.Assay5}()}, \code{\link{split.Assay5}()}, \code{\link{subset.Assay5}()} } \concept{assay5} SeuratObject/man/sub-LogMap-method.Rd0000644000176200001440000000370514520004144017131 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/logmap.R \name{[,LogMap} \alias{[,LogMap} \alias{[,LogMap,missing,missing,ANY-method} \alias{[,LogMap,character,character,ANY-method} \alias{[,LogMap,character,missing,ANY-method} \alias{[,LogMap,missing,character,ANY-method} \alias{[,LogMap,numeric,missing,ANY-method} \alias{[,LogMap,missing,numeric,ANY-method} \alias{[,LogMap,numeric,numeric,ANY-method} \title{Matrix-like Subsetting for \link[=LogMap]{Logical Maps}} \usage{ \S4method{[}{LogMap,missing,missing,ANY}(x, i, j, ..., drop = FALSE) \S4method{[}{LogMap,character,character,ANY}(x, i, j, ..., drop = FALSE) \S4method{[}{LogMap,character,missing,ANY}(x, i, j, ..., drop = FALSE) \S4method{[}{LogMap,missing,character,ANY}(x, i, j, ..., drop = FALSE) \S4method{[}{LogMap,numeric,missing,ANY}(x, i, j, ..., drop = FALSE) \S4method{[}{LogMap,missing,numeric,ANY}(x, i, j, ..., drop = FALSE) \S4method{[}{LogMap,numeric,numeric,ANY}(x, i, j, ..., drop = FALSE) } \arguments{ \item{x}{A \code{LogMap} object} \item{i, j}{Vectors of values (\code{i}) and observations (\code{j}) to pull from \code{x}} \item{...}{Arguments passed to other methods} \item{drop}{For matrices and arrays. If \code{TRUE} the result is coerced to the lowest possible dimension (see the examples). This only works for extracting elements, not for the replacement. See \code{\link[base]{drop}} for further details. } } \description{ Matrix-like Subsetting for \link[=LogMap]{Logical Maps} } \note{ \code{i} is not reordable; passing a different order for \code{i} will return a subset with rows in the same order as \code{x} } \examples{ map <- LogMap(letters[1:10]) map[['obs']] <- c(1, 3, 7) map[['entry']] <- c(2, 7, 10) map[] map[1:5, 2L] map[c("b", "c", "f"), "obs"] # Pass `drop = TRUE` to cast to `matrix` map[1:3, , drop = TRUE] # Note that `i` is non-reordable rownames(map)[1:3] map[c("b", "c", "a"), , drop = TRUE] } \keyword{internal} SeuratObject/man/Misc.Rd0000644000176200001440000000244214520004144014575 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/assay.R, R/assay5.R, % R/dimreduc.R, R/seurat.R \name{Misc} \alias{Misc} \alias{Misc<-} \alias{Misc.Assay} \alias{Misc<-.Assay} \alias{Misc.Assay5} \alias{Misc<-.Assay5} \alias{Misc.DimReduc} \alias{Misc<-.DimReduc} \alias{Misc.Seurat} \alias{Misc<-.Seurat} \title{Get and set miscellaneous data} \usage{ Misc(object, ...) Misc(object, ...) <- value \method{Misc}{Assay}(object, slot = NULL, ...) \method{Misc}{Assay}(object, slot, ...) <- value \method{Misc}{Assay5}(object, slot = NULL, ...) \method{Misc}{Assay5}(object, slot, ...) <- value \method{Misc}{DimReduc}(object, slot = NULL, ...) \method{Misc}{DimReduc}(object, slot, ...) <- value \method{Misc}{Seurat}(object, slot = NULL, ...) \method{Misc}{Seurat}(object, slot, ...) <- value } \arguments{ \item{object}{An object} \item{...}{Arguments passed to other methods} \item{value}{Data to add} \item{slot}{Name of specific bit of meta data to pull} } \value{ Miscellaneous data An object with miscellaneous data added } \description{ Get and set miscellaneous data } \examples{ # Get the misc info Misc(object = pbmc_small, slot = "example") # Add misc info Misc(object = pbmc_small, slot = "example") <- "testing_misc" } \concept{data-access} SeuratObject/man/Idents.Rd0000644000176200001440000000705014520004144015130 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/seurat.R \name{Idents} \alias{Idents} \alias{Idents<-} \alias{RenameIdents} \alias{RenameIdent} \alias{ReorderIdent} \alias{SetIdent} \alias{StashIdent} \alias{Idents.Seurat} \alias{Idents<-.Seurat} \alias{ReorderIdent.Seurat} \alias{RenameIdents.Seurat} \alias{SetIdent.Seurat} \alias{StashIdent.Seurat} \alias{droplevels.Seurat} \alias{levels.Seurat} \alias{levels<-.Seurat} \title{Get, set, and manipulate an object's identity classes} \usage{ Idents(object, ...) Idents(object, ...) <- value RenameIdents(object, ...) ReorderIdent(object, var, ...) SetIdent(object, ...) StashIdent(object, save.name, ...) \method{Idents}{Seurat}(object, ...) \method{Idents}{Seurat}(object, cells = NULL, drop = FALSE, replace = FALSE, ...) <- value \method{ReorderIdent}{Seurat}( object, var, reverse = FALSE, afxn = mean, reorder.numeric = FALSE, ... ) \method{RenameIdents}{Seurat}(object, ...) \method{SetIdent}{Seurat}(object, cells = NULL, value, ...) \method{StashIdent}{Seurat}(object, save.name = "orig.ident", ...) \method{droplevels}{Seurat}(x, ...) \method{levels}{Seurat}(x) \method{levels}{Seurat}(x) <- value } \arguments{ \item{...}{Arguments passed to other methods; for \code{RenameIdents}: named arguments as \code{old.ident = new.ident}; for \code{ReorderIdent}: arguments passed on to \code{\link{FetchData}}} \item{value}{The name of the identities to pull from object metadata or the identities themselves} \item{var}{Feature or variable to order on} \item{save.name}{Store current identity information under this name} \item{cells}{Set cell identities for specific cells} \item{drop}{Drop unused levels} \item{replace}{Replace identities for unset cells with \code{NA}} \item{reverse}{Reverse ordering} \item{afxn}{Function to evaluate each identity class based on; default is \code{\link[base]{mean}}} \item{reorder.numeric}{Rename all identity classes to be increasing numbers starting from 1 (default is FALSE)} \item{x, object}{An object} } \value{ \code{Idents}: The cell identities \code{Idents<-}: \code{object} with the cell identities changed \code{RenameIdents}: An object with selected identity classes renamed \code{ReorderIdent}: An object with \code{SetIdent}: An object with new identity classes set \code{StashIdent}: An object with the identities stashed } \description{ Get, set, and manipulate an object's identity classes } \examples{ # Get cell identity classes Idents(pbmc_small) # Set cell identity classes # Can be used to set identities for specific cells to a new level Idents(pbmc_small, cells = 1:4) <- 'a' head(Idents(pbmc_small)) # Can also set idents from a value in object metadata colnames(pbmc_small[[]]) Idents(pbmc_small) <- 'RNA_snn_res.1' levels(pbmc_small) # Rename cell identity classes # Can provide an arbitrary amount of idents to rename levels(pbmc_small) pbmc_small <- RenameIdents(pbmc_small, '0' = 'A', '2' = 'C') levels(pbmc_small) \dontrun{ head(Idents(pbmc_small)) pbmc_small <- ReorderIdent(pbmc_small, var = 'PC_1') head(Idents(pbmc_small)) } # Set cell identity classes using SetIdent cells.use <- WhichCells(pbmc_small, idents = '1') pbmc_small <- SetIdent(pbmc_small, cells = cells.use, value = 'B') head(pbmc_small[[]]) pbmc_small <- StashIdent(pbmc_small, save.name = 'idents') head(pbmc_small[[]]) # Get the levels of identity classes of a Seurat object levels(x = pbmc_small) # Reorder identity classes levels(x = pbmc_small) levels(x = pbmc_small) <- c('C', 'A', 'B') levels(x = pbmc_small) } \concept{seurat} SeuratObject/man/Images.Rd0000644000176200001440000000106014473173564015126 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/seurat.R \name{Images} \alias{Images} \title{Pull spatial image names} \usage{ Images(object, assay = NULL) } \arguments{ \item{object}{A \code{Seurat} object} \item{assay}{Name of assay to limit search to} } \value{ A list of image names } \description{ List the names of \code{SpatialImage} objects present in a \code{Seurat} object. If \code{assay} is provided, limits search to images associated with that assay } \examples{ \dontrun{ Images(object) } } \concept{data-access} SeuratObject/man/DefaultLayer-StdAssay.Rd0000644000176200001440000000123014520004144020006 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay5.R \name{DefaultLayer-StdAssay} \alias{DefaultLayer-StdAssay} \alias{DefaultLayer.StdAssay} \alias{DefaultLayer<-.StdAssay} \title{Default Layer} \usage{ \method{DefaultLayer}{StdAssay}(object, ...) \method{DefaultLayer}{StdAssay}(object, ...) <- value } \arguments{ \item{object}{An object} \item{...}{Arguments passed to other methods} \item{value}{Name of layer to set as default} } \value{ \code{DefaultLayer}: The name of the default layer \code{DefaultLayer<-}: An object with the default layer updated } \description{ Get and set the default layer } \keyword{internal} SeuratObject/man/dot-DollarNames.Assay5.Rd0000644000176200001440000000114214520004144020027 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay5.R \name{.DollarNames.Assay5} \alias{.DollarNames.Assay5} \title{Dollar-sign Autocompletion} \usage{ \method{.DollarNames}{Assay5}(x, pattern = "") } \arguments{ \item{x}{An \code{\link{Assay5}} object} \item{pattern}{ A regular expression. Only matching names are returned. } } \value{ The layer name matches for \code{pattern} } \description{ Autocompletion for \code{$} access on an \code{\link{Assay5}} object } \seealso{ \code{\link[utils:.DollarNames]{utils::.DollarNames}} } \concept{assay5} \keyword{internal} SeuratObject/man/SpatialImage-class.Rd0000644000176200001440000000171614520004144017350 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/spatial.R \docType{class} \name{SpatialImage-class} \alias{SpatialImage-class} \alias{SpatialImage} \title{The SpatialImage class} \description{ The \code{SpatialImage} class is a virtual class representing spatial information for Seurat. All spatial image information must inherit from this class for use with \code{Seurat} objects } \section{Slots}{ \describe{ \item{\code{assay}}{Name of assay to associate image data with; will give this image priority for visualization when the assay is set as the active/default assay in a \code{Seurat} object} \item{\code{key}}{A one-length character vector with the object's key; keys must be one or more alphanumeric characters followed by an underscore \dQuote{\code{_}} (regex pattern \dQuote{\code{\Sexpr[stage=build]{SeuratObject:::.KeyPattern()}}})} }} \seealso{ \code{\link{SpatialImage-methods}} for a list of required and provided methods } SeuratObject/man/as.Neighbor.Rd0000644000176200001440000000101314473173564016056 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/neighbor.R \name{as.Neighbor} \alias{as.Neighbor} \alias{as.Neighbor.Graph} \title{Coerce to a \code{Neighbor} Object} \usage{ as.Neighbor(x, ...) \method{as.Neighbor}{Graph}(x, ...) } \arguments{ \item{x}{An object to convert to \code{\link{Neighbor}}} \item{...}{Arguments passed to other methods} } \value{ A \code{\link{Neighbor}} object } \description{ Convert objects to \code{\link{Neighbor}} objects } \concept{neighbor} SeuratObject/man/RenameCells.Rd0000644000176200001440000000376414520004144016104 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/assay.R, R/assay5.R, % R/dimreduc.R, R/neighbor.R, R/seurat.R \name{RenameCells} \alias{RenameCells} \alias{RenameCells.Assay} \alias{RenameCells.Assay5} \alias{RenameCells.DimReduc} \alias{RenameCells.Neighbor} \alias{RenameCells.Seurat} \title{Rename cells} \usage{ RenameCells(object, ...) \method{RenameCells}{Assay}(object, new.names = NULL, ...) \method{RenameCells}{Assay5}(object, new.names = NULL, ...) \method{RenameCells}{DimReduc}(object, new.names = NULL, ...) \method{RenameCells}{Neighbor}(object, old.names = NULL, new.names = NULL, ...) \method{RenameCells}{Seurat}( object, add.cell.id = missing_arg(), new.names = missing_arg(), for.merge = deprecated(), ... ) } \arguments{ \item{object}{An object} \item{...}{Arguments passed to other methods} \item{new.names}{vector of new cell names} \item{old.names}{vector of old cell names} \item{add.cell.id}{prefix to add cell names} \item{for.merge}{Deprecated} } \value{ An object with new cell names } \description{ Change the cell names in all the different parts of an object. Can be useful before combining multiple objects. } \details{ If \code{add.cell.id} is set a prefix is added to existing cell names. If \code{new.names} is set these will be used to replace existing names. } \examples{ # Rename cells in an Assay head(x = colnames(x = pbmc_small[["RNA"]])) renamed.assay <- RenameCells( pbmc_small[["RNA"]], new.names = paste0("A_", colnames(x = pbmc_small[["RNA"]])) ) head(x = colnames(x = renamed.assay)) # Rename cells in a DimReduc head(x = Cells(x = pbmc_small[["pca"]])) renamed.dimreduc <- RenameCells( object = pbmc_small[["pca"]], new.names = paste0("A_", Cells(x = pbmc_small[["pca"]])) ) head(x = Cells(x = renamed.dimreduc)) # Rename cells in a Seurat object head(x = colnames(x = pbmc_small)) pbmc_small <- RenameCells(object = pbmc_small, add.cell.id = "A") head(x = colnames(x = pbmc_small)) } \concept{seurat} SeuratObject/man/as.list.SeuratCommand.Rd0000644000176200001440000000166314520004144020024 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/command.R \name{as.list.SeuratCommand} \alias{as.list.SeuratCommand} \title{Coerce a \code{SeuratCommand} to a list} \usage{ \method{as.list}{SeuratCommand}(x, complete = FALSE, ...) } \arguments{ \item{x}{A \code{\link{SeuratCommand}} object} \item{complete}{Include slots besides just parameters (eg. call string, name, timestamp)} \item{...}{Ignored} } \value{ A list with the parameters and, if \code{complete = TRUE}, the call string, name, and timestamp } \description{ Coerce a \code{SeuratCommand} to a list } \examples{ cmd <- pbmc_small[["NormalizeData.RNA"]] as.list(cmd) as.list(cmd, complete = TRUE) } \seealso{ Command log object and interaction methods \code{\link{$.SeuratCommand}()}, \code{\link{.DollarNames.SeuratCommand}()}, \code{\link{LogSeuratCommand}()}, \code{\link{SeuratCommand-class}}, \code{\link{[.SeuratCommand}()} } \concept{command} SeuratObject/man/CheckFeaturesNames.Rd0000644000176200001440000000061514520004201017374 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{CheckFeaturesNames} \alias{CheckFeaturesNames} \title{Check features names format} \usage{ CheckFeaturesNames(data) } \arguments{ \item{data}{a matrix input, rownames(data) are feature names} } \value{ \code{data} with update feature names } \description{ Check features names format } \keyword{internal} SeuratObject/man/VariableFeatures.Rd0000644000176200001440000001065714520004144017135 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/seurat.R, R/assay.R, R/assay5.R \name{HVFInfo} \alias{HVFInfo} \alias{VariableFeatures} \alias{VariableFeatures<-} \alias{SVFInfo} \alias{SpatiallyVariableFeatures} \alias{HVFInfo.Seurat} \alias{VariableFeatures.Seurat} \alias{VariableFeatures<-.Seurat} \alias{SVFInfo.Seurat} \alias{SpatiallyVariableFeatures.Seurat} \alias{HVFInfo.Assay} \alias{SpatiallyVariableFeatures.Assay} \alias{SVFInfo.Assay} \alias{VariableFeatures.Assay} \alias{VariableFeatures<-.Assay} \alias{HVFInfo.Assay5} \alias{VariableFeatures.Assay5} \alias{VariableFeatures<-.Assay5} \title{Highly Variable Features} \usage{ HVFInfo(object, method, status = FALSE, ...) VariableFeatures(object, method = NULL, ...) VariableFeatures(object, ...) <- value SVFInfo(object, method, status, ...) SpatiallyVariableFeatures(object, method, ...) \method{HVFInfo}{Seurat}( object, method = NULL, status = FALSE, assay = NULL, selection.method = deprecated(), ... ) \method{VariableFeatures}{Seurat}( object, method = NULL, assay = NULL, nfeatures = NULL, layer = NA, simplify = TRUE, selection.method = deprecated(), ... ) \method{VariableFeatures}{Seurat}(object, assay = NULL, ...) <- value \method{SVFInfo}{Seurat}( object, method = c("markvariogram", "moransi"), status = FALSE, assay = NULL, selection.method = deprecated(), ... ) \method{SpatiallyVariableFeatures}{Seurat}( object, method = "moransi", assay = NULL, decreasing = TRUE, selection.method = deprecated(), ... ) \method{HVFInfo}{Assay}(object, method, status = FALSE, selection.method = deprecated(), ...) \method{SpatiallyVariableFeatures}{Assay}( object, method = "moransi", decreasing = TRUE, selection.method = deprecated(), ... ) \method{SVFInfo}{Assay}( object, method = c("markvariogram", "moransi"), status = FALSE, selection.method = deprecated(), ... ) \method{VariableFeatures}{Assay}(object, method = NULL, selection.method = deprecated(), ...) \method{VariableFeatures}{Assay}(object, ...) <- value \method{HVFInfo}{Assay5}(object, method = NULL, status = FALSE, layer = NULL, strip = TRUE, ...) \method{VariableFeatures}{Assay5}( object, method = NULL, layer = NA, simplify = TRUE, nfeatures = Inf, selection.method = deprecated(), ... ) \method{VariableFeatures}{Assay5}(object, method = "custom", layer = NULL, ...) <- value } \arguments{ \item{object}{An object} \item{method}{Which method to pull. For \code{HVFInfo} and \code{VariableFeatures}, choose one from one of the following: \itemize{ \item \dQuote{vst} \item \dQuote{sctransform} or \dQuote{sct} \item \dQuote{mean.var.plot}, \dQuote{dispersion}, \dQuote{mvp}, or \dQuote{disp} } For \code{SVFInfo} and \code{SpatiallyVariableFeatures}, choose from: \itemize{ \item \dQuote{markvariogram} \item \dQuote{moransi} }} \item{status}{Add variable status to the resulting data frame} \item{...}{Arguments passed to other methods} \item{value}{A character vector of variable features} \item{assay}{Name of assay to pull highly variable feature information for} \item{selection.method}{\Sexpr[stage=build,results=rd]{lifecycle::badge("deprecated")}} \item{nfeatures}{Maximum number of features to select when simplifying} \item{layer}{Layer to pull variable features for} \item{simplify}{When pulling for multiple layers, combine into a single vector and select a common set of variable features for all layers} \item{decreasing}{Return features in decreasing order (most spatially variable first).} \item{strip}{Remove method/layer identifiers from highly variable data frame} } \value{ \code{HVFInfo}: A data frame with feature means, dispersion, and scaled dispersion \code{VariableFeatures}: a vector of the variable features \code{SVFInfo}: a data frame with the spatially variable features \code{SpatiallyVariableFeatures}: a character vector of the spatially variable features } \description{ Get and set variable feature information for an \code{\link{Assay}} object. \code{HVFInfo} and \code{VariableFeatures} utilize generally variable features, while \code{SVFInfo} and \code{SpatiallyVariableFeatures} are restricted to spatially variable features } \examples{ # Get the HVF info from a specific Assay in a Seurat object HVFInfo(object = pbmc_small, assay = "RNA")[1:5, ] # Get the HVF info directly from an Assay object HVFInfo(pbmc_small[["RNA"]], method = 'vst')[1:5, ] } \concept{data-access} SeuratObject/man/Stdev.Rd0000644000176200001440000000150114473173564015006 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/dimreduc.R, R/seurat.R \name{Stdev} \alias{Stdev} \alias{Stdev.DimReduc} \alias{Stdev.Seurat} \title{Get the standard deviations for an object} \usage{ Stdev(object, ...) \method{Stdev}{DimReduc}(object, ...) \method{Stdev}{Seurat}(object, reduction = "pca", ...) } \arguments{ \item{object}{An object} \item{...}{Arguments passed to other methods} \item{reduction}{Name of reduction to use} } \value{ The standard deviations } \description{ Get the standard deviations for an object } \examples{ # Get the standard deviations for each PC from the DimReduc object Stdev(object = pbmc_small[["pca"]]) # Get the standard deviations for each PC from the Seurat object Stdev(object = pbmc_small, reduction = "pca") } \concept{data-access} SeuratObject/man/AddMetaData-StdAssay.Rd0000644000176200001440000000165214520004144017526 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay5.R \name{AddMetaData-StdAssay} \alias{AddMetaData-StdAssay} \alias{AddMetaData.StdAssay} \title{Add in metadata associated with either cells or features.} \usage{ \method{AddMetaData}{StdAssay}(object, metadata, col.name = NULL) } \arguments{ \item{object}{An object} \item{metadata}{A vector, list, or data.frame with metadata to add} \item{col.name}{A name for meta data if not a named list or data.frame} } \value{ \code{object} with metadata added } \description{ Adds additional data to the object. Can be any piece of information associated with a cell (examples include read depth, alignment rate, experimental batch, or subpopulation identity) or feature (ENSG name, variance). To add cell level information, add to the Seurat object. If adding feature-level metadata, add to the Assay object (e.g. \code{object[["RNA"]]}) } \keyword{internal} SeuratObject/man/SeuratCommand-class.Rd0000644000176200001440000000170514520004144017550 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/command.R \docType{class} \name{SeuratCommand-class} \alias{SeuratCommand-class} \alias{SeuratCommand} \title{The \code{SeuratCommand} Class} \description{ The \code{SeuratCommand} is used for logging commands that are run on a \code{Seurat} object; it stores parameters and timestamps } \section{Slots}{ \describe{ \item{\code{name}}{Command name} \item{\code{time.stamp}}{Timestamp of when command was tun} \item{\code{assay.used}}{Optional name of assay used to generate \code{SeuratCommand} object} \item{\code{call.string}}{String of the command call} \item{\code{params}}{List of parameters used in the command call} }} \seealso{ Command log object and interaction methods \code{\link{$.SeuratCommand}()}, \code{\link{.DollarNames.SeuratCommand}()}, \code{\link{LogSeuratCommand}()}, \code{\link{[.SeuratCommand}()}, \code{\link{as.list.SeuratCommand}()} } \concept{command} SeuratObject/man/KeyMixin-class.Rd0000644000176200001440000000273414520004144016546 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/keymixin.R \docType{class} \name{KeyMixin-class} \alias{KeyMixin-class} \alias{KeyMixin} \alias{Key.character} \alias{Key.KeyMixin} \alias{Key<-.KeyMixin} \title{A Mixin for Keyed objects} \usage{ \method{Key}{character}(object, quiet = FALSE, ...) \method{Key}{KeyMixin}(object, ...) \method{Key}{KeyMixin}(object, ...) <- value } \arguments{ \item{object}{An object} \item{quiet}{Suppress warnings when updating characters to keys} \item{...}{Ignored} \item{value}{A key to set} } \value{ \code{Key.character}: \code{object} but as a syntactically-valid key \code{Key.KeyMixin}: The key from \code{object}; if no key set, returns \code{NULL} \code{Key<-}: \code{object} with the key set to \code{value} } \description{ A mixin (virtual class) for enabling keyed objects; provides consistent behavior for getting, setting, and validating keys } \details{ \code{Key.character}: Update a character to a key \code{Key.KeyMixin}: Get the key of a keyed object \code{Key<-}: Set the key of a keyed object } \section{Slots}{ \describe{ \item{\code{key}}{A one-length character vector with the object's key; keys must be one or more alphanumeric characters followed by an underscore \dQuote{\code{_}} (regex pattern \dQuote{\code{\Sexpr[stage=build]{SeuratObject:::.KeyPattern()}}})} }} \seealso{ \code{\link{.KeyPattern}()}, \code{\link{.RandomKey}()}, \code{\link{Key-validity}} } \concept{key} \keyword{internal} SeuratObject/man/sub-.SeuratCommand.Rd0000644000176200001440000000141414520004144017307 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/command.R \name{[.SeuratCommand} \alias{[.SeuratCommand} \title{Command Log Data Access} \usage{ \method{[}{SeuratCommand}(x, i, ...) } \arguments{ \item{x}{A \code{\link{SeuratCommand}} object} \item{i}{The name of a command log slot} \item{...}{Ignored} } \value{ \code{[}: Slot \code{i} from \code{x} } \description{ Access data from a \code{SeuratCommand} object } \examples{ cmd <- pbmc_small[["NormalizeData.RNA"]] cmd["call.string"] } \seealso{ Command log object and interaction methods \code{\link{$.SeuratCommand}()}, \code{\link{.DollarNames.SeuratCommand}()}, \code{\link{LogSeuratCommand}()}, \code{\link{SeuratCommand-class}}, \code{\link{as.list.SeuratCommand}()} } \concept{command} SeuratObject/man/dot-DollarNames.Seurat.Rd0000644000176200001440000000113714520004144020131 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/seurat.R \name{.DollarNames.Seurat} \alias{.DollarNames.Seurat} \title{Dollar-sign Autocompletion} \usage{ \method{.DollarNames}{Seurat}(x, pattern = "") } \arguments{ \item{x}{A \code{\link{Seurat}} object} \item{pattern}{ A regular expression. Only matching names are returned. } } \value{ The meta data matches for \code{pattern} } \description{ Autocompletion for \code{$} access on a \code{\link{Seurat}} object } \seealso{ \code{\link[utils:.DollarNames]{utils::.DollarNames}} } \concept{seurat} \keyword{internal} SeuratObject/man/Project.Rd0000644000176200001440000000121414473173564015330 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/seurat.R \name{Project} \alias{Project} \alias{Project<-} \alias{Project.Seurat} \alias{Project<-.Seurat} \title{Get and set project information} \usage{ Project(object, ...) Project(object, ...) <- value \method{Project}{Seurat}(object, ...) \method{Project}{Seurat}(object, ...) <- value } \arguments{ \item{object}{An object} \item{...}{Arguments passed to other methods} \item{value}{Project information to set} } \value{ Project information An object with project information added } \description{ Get and set project information } \concept{seurat} SeuratObject/man/Graph-class.Rd0000644000176200001440000000104514520004144016044 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/graph.R \docType{class} \name{Graph-class} \alias{Graph-class} \alias{Graph} \title{The Graph Class} \description{ The Graph class inherits from \code{\link[Matrix:sparseMatrix]{dgCMatrix}}. We do this to enable future expandability of graphs. } \section{Slots}{ \describe{ \item{\code{assay.used}}{Optional name of assay used to generate \code{Graph} object} }} \seealso{ \code{\link[Matrix]{dgCMatrix-class}} Other graph: \code{\link{as.Graph}()} } \concept{graph} SeuratObject/man/dot-SparseSlots.Rd0000644000176200001440000000143014520004144016744 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/sparse.R \name{.SparseSlots} \alias{.SparseSlots} \alias{.SparseSlots.CsparseMatrix} \alias{.SparseSlots.RsparseMatrix} \alias{.SparseSlots.spam} \title{Identify Sparse Slots} \usage{ .SparseSlots(x, type = c("pointers", "indices", "entries")) \method{.SparseSlots}{CsparseMatrix}(x, type = c("pointers", "entries", "indices")) \method{.SparseSlots}{RsparseMatrix}(x, type = c("pointers", "indices", "entries")) \method{.SparseSlots}{spam}(x, type = c("pointers", "indices", "entries")) } \arguments{ \item{x}{A sparse matrix} \item{type}{...} } \value{ ... } \description{ Identify Sparse Slots } \seealso{ \code{\link{IsSparse}()}, \code{\link{RegisterSparseMatrix}()} } \concept{sparse} \keyword{internal} SeuratObject/man/Seurat-validity.Rd0000644000176200001440000000123714520004144016771 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/seurat.R \name{Seurat-validity} \alias{Seurat-validity} \title{Seurat Object Validity} \description{ Validation of \code{Seurat} objects is handled by \code{\link[methods]{validObject}} } \seealso{ \code{\link[methods]{validObject}} Seurat object, validity, and interaction methods \code{\link{$.Seurat}()}, \code{\link{Seurat-class}}, \code{\link{[[.Seurat}()}, \code{\link{[[<-,Seurat,NULL}}, \code{\link{[[<-,Seurat}}, \code{\link{dim.Seurat}()}, \code{\link{dimnames.Seurat}()}, \code{\link{merge.Seurat}()}, \code{\link{names.Seurat}()}, \code{\link{subset.Seurat}()} } \concept{seurat} SeuratObject/man/JS.Rd0000644000176200001440000000177314473173564014250 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/jackstraw.R, R/dimreduc.R \name{JS} \alias{JS} \alias{JS<-} \alias{JS.JackStrawData} \alias{JS<-.JackStrawData} \alias{JS.DimReduc} \alias{JS<-.DimReduc} \title{Get and set JackStraw information} \usage{ JS(object, ...) JS(object, ...) <- value \method{JS}{JackStrawData}(object, slot, ...) \method{JS}{JackStrawData}(object, slot, ...) <- value \method{JS}{DimReduc}(object, slot = NULL, ...) \method{JS}{DimReduc}(object, slot = NULL, ...) <- value } \arguments{ \item{object}{An object} \item{...}{Arguments passed to other methods} \item{value}{JackStraw information} \item{slot}{Name of slot to store JackStraw scores to Can shorten to 'empirical', 'fake', 'full', or 'overall'} } \value{ \code{JS}: either a \code{\link{JackStrawData}} object or the specified jackstraw data \code{JS<-}: \code{object} with the update jackstraw information } \description{ Get and set JackStraw information } \concept{jackstraw} SeuratObject/man/names.Seurat.Rd0000644000176200001440000000177014520004144016252 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/seurat.R \name{names.Seurat} \alias{names.Seurat} \title{Subobject Names} \usage{ \method{names}{Seurat}(x) } \arguments{ \item{x}{A \code{\link{Seurat}} object} } \value{ The names of all of the following subobjects within \code{x}: \itemize{ \item \link[=Assay]{v3} and \link[=Assay5]{v5} assays \item \link[=DimReduc]{dimensional reductions} \item \link[=SpatialImage]{images} and \link[=FOV]{FOVs} \item \link[=Graph]{nearest-neighbor graphs} } } \description{ Get the names of subobjects within a \code{\link{Seurat}} object } \examples{ names(pbmc_small) } \seealso{ Seurat object, validity, and interaction methods \code{\link{$.Seurat}()}, \code{\link{Seurat-class}}, \code{\link{Seurat-validity}}, \code{\link{[[.Seurat}()}, \code{\link{[[<-,Seurat,NULL}}, \code{\link{[[<-,Seurat}}, \code{\link{dim.Seurat}()}, \code{\link{dimnames.Seurat}()}, \code{\link{merge.Seurat}()}, \code{\link{subset.Seurat}()} } \concept{seurat} SeuratObject/man/dot-CreateStdAssay.Rd0000644000176200001440000000473114520004144017350 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/assay5.R \name{.CreateStdAssay} \alias{.CreateStdAssay} \alias{.CreateStdAssay.default} \alias{.CreateStdAssay.list} \alias{.CreateStdAssay.Matrix} \alias{.CreateStdAssay.matrix} \title{Generic Assay Creation} \usage{ .CreateStdAssay( counts, min.cells = 0, min.features = 0, cells = NULL, features = NULL, transpose = FALSE, type = "Assay5", ... ) \method{.CreateStdAssay}{default}( counts, min.cells = 0, min.features = 0, cells = NULL, features = NULL, transpose = FALSE, type = "Assay5", layer = "counts", ... ) \method{.CreateStdAssay}{list}( counts, min.cells = 0, min.features = 0, cells = NULL, features = NULL, transpose = FALSE, type = "Assay5", csum = Matrix::colSums, fsum = Matrix::rowSums, ... ) \method{.CreateStdAssay}{Matrix}( counts, min.cells = 0, min.features = 0, cells = NULL, features = NULL, transpose = FALSE, type = "Assay5", layer = "counts", ... ) \method{.CreateStdAssay}{matrix}( counts, min.cells = 0, min.features = 0, cells = NULL, features = NULL, transpose = FALSE, type = "Assay5", layer = "counts", ... ) } \arguments{ \item{counts}{A two-dimensional expression matrix} \item{min.cells}{Include features detected in at least this many cells; will subset the counts matrix as well. To reintroduce excluded features, create a new object with a lower cutoff} \item{min.features}{Include cells where at least this many features are detected} \item{cells}{Vector of cell names} \item{features}{Vector of feature names} \item{type}{Type of assay object to create; must be the name of a class that's derived from \code{\link{StdAssay}}} \item{...}{Extra parameters passed to \code{\link[methods]{new}} for assay creation; used to set slots not defined by \code{\link{StdAssay}}} \item{layer}{Name of layer to store \code{counts} as} \item{csum}{Function for calculating cell sums} \item{fsum}{Function for calculating feature sums} } \value{ An object of class \code{type} with a layer named \code{layer} containing the data found in \code{counts} } \description{ Create an assay object; runs a standardized filtering scheme that works regardless of the direction of the data (eg. cells as columns and features as rows or vice versa) and creates an assay object based on the initialization scheme defined for \code{\link{StdAssay}}-derived class \code{type} } \concept{assay} \keyword{internal} SeuratObject/man/Assay5-validity.Rd0000644000176200001440000000224414520004144016672 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay5.R \name{Assay5-validity} \alias{Assay5-validity} \title{V5 Assay Validity} \description{ Validation of \code{Assay5} objects is handled by \code{\link[methods]{validObject}} } \section{Layer Validation}{ blah } \section{Key Validation}{ Keys must be a one-length character vector; a key must be composed of one of the following: \itemize{ \item An empty string (eg. \dQuote{\code{''}}) where \code{nzchar() == 0} \item An string composed of one or more alphanumeric values (both lower- and upper-case) that ends with an underscore (\dQuote{\code{_}}); the first character must be a letter } Keys that are not empty strings are validated with the regex \dQuote{\code{\Sexpr[stage=build]{SeuratObject:::.KeyPattern()}}} } \seealso{ \code{\link[methods]{validObject}} v5 Assay object, validity, and interaction methods: \code{\link{$.Assay5}()}, \code{\link{Assay5-class}}, \code{\link{[.Assay5}()}, \code{\link{[[.Assay5}()}, \code{\link{dim.Assay5}()}, \code{\link{dimnames.Assay5}()}, \code{\link{merge.Assay5}()}, \code{\link{split.Assay5}()}, \code{\link{subset.Assay5}()} } \concept{assay5} SeuratObject/man/ClassKey.Rd0000644000176200001440000000122714520004144015420 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{ClassKey} \alias{ClassKey} \title{Generate a Class Key} \usage{ ClassKey(class, package = NULL) } \arguments{ \item{class}{Class name} \item{package}{Optional name of package; by default, will search namespaces of loaded packages to determine the providing package} } \value{ The class key (\dQuote{\code{package:class}}) } \description{ Generate class keys for S4 classes. A class key follows the following structure: \dQuote{\code{package:class}} } \examples{ ClassKey("Seurat") } \seealso{ \code{\link{s4list}} } \concept{s4list} \concept{utils} \keyword{internal} SeuratObject/man/JackStrawData-methods.Rd0000644000176200001440000000270514473173564020054 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/jackstraw.R \name{JackStrawData-methods} \alias{JackStrawData-methods} \alias{.DollarNames.JackStrawData} \alias{$.JackStrawData} \alias{as.logical.JackStrawData} \alias{show,JackStrawData-method} \title{\code{JackStrawData} Methods} \usage{ \method{.DollarNames}{JackStrawData}(x, pattern = "") \method{$}{JackStrawData}(x, i, ...) \method{as.logical}{JackStrawData}(x, ...) \S4method{show}{JackStrawData}(object) } \arguments{ \item{x, object}{A \code{\link{JackStrawData}} object} \item{pattern}{ A regular expression. Only matching names are returned. } \item{i}{A \code{JackStrawData} slot name} \item{...}{Ignored} } \value{ \code{$}: Slot \code{i} from \code{x} \code{as.logical}: \code{TRUE} if empirical p-values have been calculated otherwise \code{FALSE} \code{show}: Prints summary to \code{\link[base]{stdout}} and invisibly returns \code{NULL} } \description{ Methods for \code{\link{JackStrawData}} objects for generics defined in other packages } \section{Functions}{ \itemize{ \item \code{.DollarNames(JackStrawData)}: Autocompletion for \code{$} access on a \code{JackStrawData} object \item \code{$}: Access data from a \code{JackStrawData} object \item \code{as.logical(JackStrawData)}: Have empirical p-values for a \code{JackStrawData} object been calculated \item \code{show(JackStrawData)}: Overview of a \code{JackStrawData} object }} \concept{jackstraw} SeuratObject/man/print.DimReduc.Rd0000644000176200001440000000220214520004144016523 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/dimreduc.R \name{print.DimReduc} \alias{print.DimReduc} \alias{print} \title{Print Top Feature Loadings} \usage{ \method{print}{DimReduc}(x, dims = 1:5, nfeatures = 20, projected = FALSE, ...) } \arguments{ \item{x}{A \code{\link{DimReduc}} object} \item{dims}{Number of dimensions to display} \item{nfeatures}{Number of genes to display} \item{projected}{Use projected slot} \item{...}{Ignored} } \value{ Displays set of features defining the components and invisibly returns \code{x} } \description{ Prints a set of features that most strongly define a set of components; \strong{note}: requires feature loadings to be present in order to work } \examples{ pca <- pbmc_small[["pca"]] print(pca) } \seealso{ \code{\link[base]{cat}} Dimensional reduction object, validity, and interaction methods \code{\link{CreateDimReducObject}()}, \code{\link{DimReduc-class}}, \code{\link{DimReduc-validity}}, \code{\link{[.DimReduc}()}, \code{\link{[[.DimReduc}()}, \code{\link{dim.DimReduc}()}, \code{\link{merge.DimReduc}()}, \code{\link{subset.DimReduc}()} } \concept{dimreduc} SeuratObject/man/dot-CalcN.Rd0000644000176200001440000000071214520004144015444 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R \name{.CalcN} \alias{.CalcN} \title{Calculate nCount and nFeature} \usage{ .CalcN(object, ...) } \arguments{ \item{object}{An assay-like object} \item{...}{Arguments passed to other methods} } \value{ A named list with ... } \description{ Calculate nCount and nFeature } \examples{ calcn <- .CalcN(pbmc_small[["RNA"]]) head(as.data.frame(calcn)) } \keyword{internal} SeuratObject/man/subset.Assay.Rd0000644000176200001440000000166614520004144016275 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay.R \name{subset.Assay} \alias{subset.Assay} \title{Subset an Assay} \usage{ \method{subset}{Assay}(x, cells = NULL, features = NULL, ...) } \arguments{ \item{x}{An \code{\link{Assay}} object} \item{cells}{Cell names} \item{features}{Feature names} \item{...}{Ignored} } \value{ \code{x} with just the cells and features specified by \code{cells} and \code{features} } \description{ Subset an Assay } \examples{ rna <- pbmc_small[["RNA"]] rna2 <- subset(rna, features = VariableFeatures(rna)) rna2 } \seealso{ v3 Assay object, validity, and interaction methods: \code{\link{$.Assay}()}, \code{\link{Assay-class}}, \code{\link{Assay-validity}}, \code{\link{CreateAssayObject}()}, \code{\link{[.Assay}()}, \code{\link{[[.Assay}()}, \code{\link{dim.Assay}()}, \code{\link{dimnames.Assay}()}, \code{\link{merge.Assay}()}, \code{\link{split.Assay}()} } \concept{assay} SeuratObject/man/dot-IsFutureSeurat.Rd0000644000176200001440000000200714520004144017415 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/zzz.R \name{.IsFutureSeurat} \alias{.IsFutureSeurat} \alias{IsFutureSeurat} \title{Test Future Compatibility with \pkg{Seurat}} \usage{ .IsFutureSeurat(version, lib.loc = NULL) } \arguments{ \item{version}{A version string or object of class \code{\link{package_version}}} \item{lib.loc}{a character vector of directory names of \R libraries, or \code{NULL}. The default value of \code{NULL} corresponds to all libraries currently known. If the default is used, the loaded packages and namespaces are searched before the libraries.} } \value{ \code{TRUE} if \pkg{SeuratObject} and/or \pkg{Seurat} } \description{ Check to see if \pkg{SeuratObject} and/or \pkg{Seurat} are at least a specific version or if they're configured to act as if they're a specific version (see details below). This allows testing compatibility with future requirements for both \pkg{SeuratObject} and \pkg{Seurat} } \details{ Blah blah blah } \keyword{internal} SeuratObject/man/StdAssay-class.Rd0000644000176200001440000000500414520004144016535 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay5.R \docType{class} \name{StdAssay-class} \alias{StdAssay-class} \alias{StdAssay} \title{Core Assay Infrastructure} \description{ The \code{StdAssay} class is a virtual class that provides core infrastructure for assay data in \pkg{Seurat}. Assays contain expression data (layers) and associated feature-level meta data. Derived classes (eg. \link[=Assay5]{the v5 Assay}) may optionally define additional functionality } \section{Slots}{ \describe{ \item{\code{layers}}{A named list containing expression matrices; each matrix should be a two-dimensional object containing some subset of cells and features defined in the \code{cells} and \code{features} slots. Cell and feature membership is recorded in the \code{cells} and \code{features} slots, respectively} \item{\code{cells}}{A \link[=LogMap]{logical mapping} of cell names and layer membership; this map contains all the possible cells that this assay can contain. New layers must have some subset of cells present in this map} \item{\code{features}}{A \link[=LogMap]{logical mapping} of feature names and layer membership; this map contains all the possible features that this assay can contain. New layers must have some subset of features present in this map} \item{\code{default}}{A one-length integer with the end index of the \link[=DefaultLayer]{default layer}; the default layer be all layers up to and including the layer at index \code{default}} \item{\code{assay.orig}}{Original assay that this assay is based off of; used to track assay provenance} \item{\code{meta.data}}{A \link[base:data.frame]{data frame} with feature-level meta data; should have the same number of rows as \code{features}} \item{\code{misc}}{A named list of unstructured miscellaneous data} \item{\code{key}}{A one-length character vector with the object's key; keys must be one or more alphanumeric characters followed by an underscore \dQuote{\code{_}} (regex pattern \dQuote{\code{\Sexpr[stage=build]{SeuratObject:::.KeyPattern()}}})} }} \seealso{ \code{\link{Assay5-class}} \code{\link{Assay5T-class}} v5 Standard Assay object, validity, and interaction methods \code{\link{$.StdAssay}()}, \code{\link{.DollarNames.StdAssay}()}, \code{\link{StdAssay-validity}}, \code{\link{[.StdAssay}()}, \code{\link{[[.StdAssay}()}, \code{\link{dim.StdAssay}()}, \code{\link{dimnames.StdAssay}()}, \code{\link{show,StdAssay-method}}, \code{\link{split.StdAssay}()}, \code{\link{subset.StdAssay}()} } \concept{stdassay} \keyword{internal} SeuratObject/man/dim.StdAssay.Rd0000644000176200001440000000146314520004144016207 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay5.R \name{dim.StdAssay} \alias{dim.StdAssay} \title{Feature and Cell Numbers} \usage{ \method{dim}{StdAssay}(x) } \arguments{ \item{x}{An \code{\link{Assay5}} object} } \value{ A two-length numeric vector with the total number of features and cells in \code{x} } \description{ Feature and Cell Numbers } \seealso{ v5 Standard Assay object, validity, and interaction methods \code{\link{$.StdAssay}()}, \code{\link{.DollarNames.StdAssay}()}, \code{\link{StdAssay-class}}, \code{\link{StdAssay-validity}}, \code{\link{[.StdAssay}()}, \code{\link{[[.StdAssay}()}, \code{\link{dimnames.StdAssay}()}, \code{\link{show,StdAssay-method}}, \code{\link{split.StdAssay}()}, \code{\link{subset.StdAssay}()} } \concept{stdassay} \keyword{internal} SeuratObject/man/figures/0000755000176200001440000000000014520004144015055 5ustar liggesusersSeuratObject/man/figures/lifecycle-defunct.svg0000644000176200001440000000170414520004144021165 0ustar liggesuserslifecyclelifecycledefunctdefunct SeuratObject/man/figures/lifecycle-maturing.svg0000644000176200001440000000170614520004144021365 0ustar liggesuserslifecyclelifecyclematuringmaturing SeuratObject/man/figures/lifecycle-archived.svg0000644000176200001440000000170714520004144021325 0ustar liggesusers lifecyclelifecyclearchivedarchived SeuratObject/man/figures/lifecycle-questioning.svg0000644000176200001440000000171414520004144022103 0ustar liggesuserslifecyclelifecyclequestioningquestioning SeuratObject/man/figures/lifecycle-superseded.svg0000644000176200001440000000171314520004144021700 0ustar liggesusers lifecyclelifecyclesupersededsuperseded SeuratObject/man/figures/lifecycle-stable.svg0000644000176200001440000000167414520004144021015 0ustar liggesuserslifecyclelifecyclestablestable SeuratObject/man/figures/lifecycle-experimental.svg0000644000176200001440000000171614520004144022235 0ustar liggesuserslifecyclelifecycleexperimentalexperimental SeuratObject/man/figures/lifecycle-deprecated.svg0000644000176200001440000000171214520004144021634 0ustar liggesuserslifecyclelifecycledeprecateddeprecated SeuratObject/man/sub-.Assay.Rd0000644000176200001440000000243414520004144015630 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay.R \name{[.Assay} \alias{[.Assay} \alias{[<-,Assay,character,ANY,ANY-method} \title{Layer Data} \usage{ \method{[}{Assay}(x, i = missing_arg(), j = missing_arg(), ...) \S4method{[}{Assay,character,ANY,ANY}(x, i, j, ...) <- value } \arguments{ \item{x}{An \code{\link{Assay}} object} \item{i}{Name of layer data to get or set} \item{j}{Ignored} \item{...}{Arguments passed to \code{\link{LayerData}}} \item{value}{A matrix-like object to add as a new layer} } \value{ \code{[}: The layer data for layer \code{i} \code{[<-}: \code{x} with layer data \code{value} saved as \code{i} } \description{ Get and set layer data } \examples{ rna <- pbmc_small[["RNA"]] # Get a vector of layer names in this assay rna[] # Fetch layer data rna["data"][1:10, 1:4] # Set layer data rna["data"] <- rna["counts"] rna["data"][1:10, 1:4] } \seealso{ \code{\link{LayerData}} v3 Assay object, validity, and interaction methods: \code{\link{$.Assay}()}, \code{\link{Assay-class}}, \code{\link{Assay-validity}}, \code{\link{CreateAssayObject}()}, \code{\link{[[.Assay}()}, \code{\link{dim.Assay}()}, \code{\link{dimnames.Assay}()}, \code{\link{merge.Assay}()}, \code{\link{split.Assay}()}, \code{\link{subset.Assay}()} } \concept{assay} SeuratObject/man/FOV-validity.Rd0000644000176200001440000000060114520004144016152 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/fov.R \name{FOV-validity} \alias{FOV-validity} \title{FOV Validity} \description{ Validation of \code{FOV} objects is handled by \code{\link[methods]{validObject}} } \section{Boundary Validation}{ blah } \section{Molecule Validation}{ blah } \seealso{ \code{\link[methods]{validObject}} } \concept{fov} SeuratObject/man/cash-.StdAssay.Rd0000644000176200001440000000172614520004144016433 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay5.R \name{$.StdAssay} \alias{$.StdAssay} \alias{$<-.StdAssay} \title{Layer Data} \usage{ \method{$}{StdAssay}(x, i) \method{$}{StdAssay}(x, i) <- value } \arguments{ \item{x}{An \code{\link{Assay5}} object} \item{i}{Name of layer data to get or set} \item{value}{A matrix-like object to add as a new layer} } \value{ {$}: Layer data for layer \code{i} \code{$<-}: \code{x} with layer data \code{value} saved as \code{i} } \description{ Get and set layer data } \seealso{ v5 Standard Assay object, validity, and interaction methods \code{\link{.DollarNames.StdAssay}()}, \code{\link{StdAssay-class}}, \code{\link{StdAssay-validity}}, \code{\link{[.StdAssay}()}, \code{\link{[[.StdAssay}()}, \code{\link{dim.StdAssay}()}, \code{\link{dimnames.StdAssay}()}, \code{\link{show,StdAssay-method}}, \code{\link{split.StdAssay}()}, \code{\link{subset.StdAssay}()} } \concept{stdassay} \keyword{internal} SeuratObject/man/old-assign.Rd0000644000176200001440000000152214520004144015740 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/seurat.R \name{old-assign} \alias{old-assign} \alias{[[<-,Seurat,character,ANY,ANY-method} \title{Original double-bracket assign} \usage{ \S4method{[[}{Seurat,character,ANY,ANY}(x, i, j, ...) <- value } \arguments{ \item{x}{A \code{\link{Seurat}} object} \item{i}{The name to store a subobject or various cell-level meta data as} \item{value}{New subobject or cell-level meta data} } \value{ \code{x} with \code{value} stored as \code{i} } \description{ This function has been replaced with value-specific double-bracket assign methods and should generally not be called } \seealso{ See \link[=$.Seurat]{here} for adding metadata with \code{[[<-}, and \link[=[[<-,Seurat,NULL]{here} for removing subobjects and cell-level meta data with \code{[[<-} } \keyword{internal} SeuratObject/man/Overlay.Rd0000644000176200001440000000312014520004201015307 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/centroids.R, R/segmentation.R, % R/molecules.R, R/fov.R \name{Overlay} \alias{Overlay} \alias{Overlay,Centroids,SpatialPolygons-method} \alias{Overlay,Segmentation,SpatialPolygons-method} \alias{Overlay,Molecules,SpatialPolygons-method} \alias{Overlay,FOV,Spatial-method} \alias{Overlay,FOV,SpatialPolygons-method} \alias{Overlay,FOV,FOV-method} \title{Overlay \code{Spatial} Objects Over One Another} \usage{ Overlay(x, y, invert = FALSE, ...) \S4method{Overlay}{Centroids,SpatialPolygons}(x, y, invert = FALSE, ...) \S4method{Overlay}{Segmentation,SpatialPolygons}(x, y, invert = FALSE, ...) \S4method{Overlay}{Molecules,SpatialPolygons}(x, y, invert = FALSE, ...) \S4method{Overlay}{FOV,Spatial}(x, y, invert = FALSE, ...) \S4method{Overlay}{FOV,SpatialPolygons}(x, y, invert = FALSE, ...) \S4method{Overlay}{FOV,FOV}(x, y, invert = FALSE, ...) } \arguments{ \item{x}{Query \code{Spatial} object} \item{y}{Target \code{Spatial} object} \item{invert}{Invert the overlay and return only the components of \code{x} that fall \emph{outside} the bounds of \code{y}} \item{...}{Ignored} } \value{ \code{x} with only the components that fall within the bounds of \code{y} } \description{ Create an overlay of some query spatial object (\code{x}) against some target object (\code{y}). Basically, find all components of a query that fall within the bounds of a target spatial region } \note{ This function requires the \href{https://cran.r-project.org/package=sf}{\pkg{sf}} package to be installed } \concept{spatial} SeuratObject/man/reexports.Rd0000644000176200001440000000112714520004144015734 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/zzz.R \docType{import} \name{reexports} \alias{reexports} \alias{plan} \alias{intersect} \alias{handlers} \alias{with_progress} \title{Objects exported from other packages} \keyword{internal} \description{ These objects are imported from other packages. Follow the links below to see their documentation. \describe{ \item{future}{\code{\link[future]{plan}}} \item{generics}{\code{\link[generics:setops]{intersect}}} \item{progressr}{\code{\link[progressr]{handlers}}, \code{\link[progressr]{with_progress}}} }} SeuratObject/man/UpdateSeuratObject.Rd0000644000176200001440000000122214473173564017456 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/seurat.R \name{UpdateSeuratObject} \alias{UpdateSeuratObject} \title{Update old Seurat object to accommodate new features} \usage{ UpdateSeuratObject(object) } \arguments{ \item{object}{Seurat object} } \value{ Returns a Seurat object compatible with latest changes } \description{ Updates Seurat objects to new structure for storing data/calculations. For Seurat v3 objects, will validate object structure ensuring all keys and feature names are formed properly. } \examples{ \dontrun{ updated_seurat_object = UpdateSeuratObject(object = old_seurat_object) } } \concept{seurat} SeuratObject/man/dimnames.Assay5.Rd0000644000176200001440000000225714520004144016647 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay5.R \name{dimnames.Assay5} \alias{dimnames.Assay5} \alias{dimnames<-.Assay5} \title{Assay-Level Feature and Cell Names} \usage{ \method{dimnames}{Assay5}(x) \method{dimnames}{Assay5}(x) <- value } \arguments{ \item{x}{An \code{\link{Assay5}} object} \item{value}{A two-length list with updated feature and/or cells names} } \value{ \code{dimnames}: A two-length list with the following values: \itemize{ \item A character vector with all features in \code{x} \item A character vector with all cells in \code{x} } \code{dimnames<-}: \code{x} with the feature and/or cell names updated to \code{value} } \description{ Get and set feature and cell names in v5 Assays } \seealso{ v5 Assay object, validity, and interaction methods: \code{\link{$.Assay5}()}, \code{\link{Assay5-class}}, \code{\link{Assay5-validity}}, \code{\link{[.Assay5}()}, \code{\link{[[.Assay5}()}, \code{\link{dim.Assay5}()}, \code{\link{merge.Assay5}()}, \code{\link{split.Assay5}()}, \code{\link{subset.Assay5}()} \code{\link{Cells}()}, \code{\link{dimnames.Assay}()}, \code{\link{dimnames.Seurat}()} } \concept{assay5} \concept{dimnames} SeuratObject/man/show-DimReduc-method.Rd0000644000176200001440000000102214520004144017623 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/dimreduc.R \name{show,DimReduc-method} \alias{show,DimReduc-method} \title{Dimensional Reduction Overview} \usage{ \S4method{show}{DimReduc}(object) } \arguments{ \item{object}{A dimensional reduction} } \value{ Prints summary to \code{\link[base]{stdout}} and invisibly returns \code{NULL} } \description{ Overview of a \code{\link{DimReduc}} object } \examples{ pca <- pbmc_small[["pca"]] pca } \seealso{ \code{\link{DimReduc}} } \keyword{internal} SeuratObject/man/SaveSeuratRds.Rd0000644000176200001440000000735114525215072016452 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/seurat.R \name{SaveSeuratRds} \alias{SaveSeuratRds} \alias{LoadSeuratRds} \title{Save and Load \code{Seurat} Objects from Rds files} \usage{ SaveSeuratRds( object, file = NULL, move = TRUE, destdir = deprecated(), relative = FALSE, ... ) LoadSeuratRds(file, ...) } \arguments{ \item{object}{A \code{\link{Seurat}} object} \item{file}{Path to save \code{object} to; defaults to \code{file.path(getwd(), paste0(Project(object), ".Rds"))}} \item{move}{Move on-disk layers into \code{dirname(file)}} \item{destdir}{\Sexpr[stage=build,results=rd]{lifecycle::badge("deprecated")}} \item{relative}{Save relative paths instead of absolute ones} \item{...}{ Arguments passed on to \code{\link[base:readRDS]{base::saveRDS}}, \code{\link[base:readRDS]{base::readRDS}} \describe{ \item{\code{ascii}}{a logical. If \code{TRUE} or \code{NA}, an ASCII representation is written; otherwise (default), a binary one is used. See the comments in the help for \code{\link[base]{save}}.} \item{\code{version}}{the workspace format version to use. \code{NULL} specifies the current default version (3). The only other supported value is 2, the default from \R 1.4.0 to \R 3.5.0.} \item{\code{compress}}{a logical specifying whether saving to a named file is to use \code{"gzip"} compression, or one of \code{"gzip"}, \code{"bzip2"} or \code{"xz"} to indicate the type of compression to be used. Ignored if \code{file} is a connection.} \item{\code{refhook}}{a hook function for handling reference objects.} }} } \value{ Invisibly returns \code{file} } \description{ Save and Load \code{Seurat} Objects from Rds files } \note{ This function requires the \href{https://cran.r-project.org/package=fs}{\pkg{fs}} package to be installed } \section{Progress Updates with \pkg{progressr}}{ This function uses \href{https://cran.r-project.org/package=progressr}{\pkg{progressr}} to render status updates and progress bars. To enable progress updates, wrap the function call in \code{\link[progressr]{with_progress}} or run \code{\link[progressr:handlers]{handlers(global = TRUE)}} before running this function. For more details about \pkg{progressr}, please read \href{https://progressr.futureverse.org/articles/progressr-intro.html}{\code{vignette("progressr-intro")}} } \examples{ if (requireNamespace("fs", quietly = TRUE)) { # Write out with DelayedArray if (requireNamespace("HDF5Array", quietly = TRUE)) { pbmc <- pbmc_small pbmc[["disk"]] <- CreateAssay5Object(list( mem = LayerData(pbmc, "counts"), disk = as(LayerData(pbmc, "counts"), "HDF5Array") )) # Save `pbmc` to an Rds file out <- tempfile(fileext = ".Rds") SaveSeuratRds(pbmc, file = out) # Object cache obj <- readRDS(out) Tool(obj, "SaveSeuratRds") # Load the saved object with on-disk layers back into memory pbmc2 <- LoadSeuratRds(out) pbmc2 pbmc2[["disk"]] } # Write out with BPCells if (requireNamespace("BPCells", quietly = TRUE)) { pbmc <- pbmc_small bpm <- BPCells::write_matrix_dir(LayerData(pbmc, "counts"), dir = tempfile()) bph <- BPCells::write_matrix_hdf5( LayerData(pbmc, "counts"), path = tempfile(fileext = ".h5"), group = "counts" ) pbmc[["disk"]] <- CreateAssay5Object(list(dir = bpm, h5 = bph)) # Save `pbmc` to an Rds file out <- tempfile(fileext = ".Rds") SaveSeuratRds(pbmc, file = out) # Object cache obj <- readRDS(out) Tool(obj, "SaveSeuratRds") # Load the saved object with on-disk layers back into memory pbmc2 <- LoadSeuratRds(out) pbmc2 pbmc2[["disk"]] } } } \seealso{ \code{\link{saveRDS}()} \code{\link{readRDS}()} } \concept{utils} SeuratObject/man/Version.Rd0000644000176200001440000000066714473173564015362 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/seurat.R \name{Version} \alias{Version} \alias{Version.Seurat} \title{Get Version Information} \usage{ Version(object, ...) \method{Version}{Seurat}(object, ...) } \arguments{ \item{object}{An object} \item{...}{Arguments passed to other methods} } \description{ Get Version Information } \examples{ Version(pbmc_small) } \concept{data-access} SeuratObject/man/sub-.DimReduc.Rd0000644000176200001440000000242314520004144016242 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/dimreduc.R \name{[.DimReduc} \alias{[.DimReduc} \title{Get Feature Loadings} \usage{ \method{[}{DimReduc}(x, i, j, drop = FALSE, ...) } \arguments{ \item{x}{A \code{\link{DimReduc}} object} \item{i}{Feature identifiers or indices} \item{j}{Dimension identifiers or indices} \item{drop}{Coerce the result to the lowest possible dimension; see \code{\link{drop}} for further details} \item{...}{Arguments passed to other methods} } \value{ Feature loadings for features \code{i} and dimensions \code{j} } \description{ Pull feature loadings from a \link[=DimReduc]{dimensional reduction} } \details{ \code{[} does not distinguish between projected and unprojected feature loadings; to select whether projected or unprojected loadings should be pulled, please use \code{\link{Loadings}} } \examples{ pca <- pbmc_small[["pca"]] pca[1:10, 1:5] } \seealso{ \code{\link{Loadings}} Dimensional reduction object, validity, and interaction methods \code{\link{CreateDimReducObject}()}, \code{\link{DimReduc-class}}, \code{\link{DimReduc-validity}}, \code{\link{[[.DimReduc}()}, \code{\link{dim.DimReduc}()}, \code{\link{merge.DimReduc}()}, \code{\link{print.DimReduc}()}, \code{\link{subset.DimReduc}()} } \concept{dimreduc} SeuratObject/man/DefaultLayer.Rd0000644000176200001440000000146114520004201016255 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/assay.R, R/assay5.R \name{DefaultLayer} \alias{DefaultLayer} \alias{DefaultLayer<-} \alias{DefaultLayer.Assay} \alias{DefaultLayer.Assay5} \alias{DefaultLayer<-.Assay5} \title{Default Layer} \usage{ DefaultLayer(object, ...) DefaultLayer(object, ...) <- value \method{DefaultLayer}{Assay}(object, ...) \method{DefaultLayer}{Assay5}(object, ...) \method{DefaultLayer}{Assay5}(object, ...) <- value } \arguments{ \item{object}{An object} \item{...}{Arguments passed to other methods} \item{value}{Name of layer to set as default} } \value{ \code{DefaultLayer}: The name of the default layer \code{DefaultLayer<-}: An object with the default layer updated } \description{ Get and set the default layer } \concept{assay5} SeuratObject/man/Loadings.Rd0000644000176200001440000000262514473173564015471 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/dimreduc.R, R/seurat.R \name{Loadings} \alias{Loadings} \alias{Loadings<-} \alias{Loadings.DimReduc} \alias{Loadings<-.DimReduc} \alias{Loadings.Seurat} \title{Get and set feature loadings} \usage{ Loadings(object, ...) Loadings(object, ...) <- value \method{Loadings}{DimReduc}(object, projected = FALSE, ...) \method{Loadings}{DimReduc}(object, projected = TRUE, ...) <- value \method{Loadings}{Seurat}(object, reduction = "pca", projected = FALSE, ...) } \arguments{ \item{object}{An object} \item{...}{Arguments passed to other methods} \item{value}{Feature loadings to add} \item{projected}{Pull the projected feature loadings?} \item{reduction}{Name of reduction to pull feature loadings for} } \value{ \code{Loadings}: the feature loadings for \code{object} \code{Loadings<-}: \code{object} with the updated loadings } \description{ Get and set feature loadings } \examples{ # Get the feature loadings for a given DimReduc Loadings(object = pbmc_small[["pca"]])[1:5,1:5] # Set the feature loadings for a given DimReduc new.loadings <- Loadings(object = pbmc_small[["pca"]]) new.loadings <- new.loadings + 0.01 Loadings(object = pbmc_small[["pca"]]) <- new.loadings # Get the feature loadings for a specified DimReduc in a Seurat object Loadings(object = pbmc_small, reduction = "pca")[1:5,1:5] } \concept{data-access} SeuratObject/man/DefaultAssay.Rd0000644000176200001440000000350214520004144016265 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/graph.R, R/assay.R, R/assay5.R, % R/command.R, R/dimreduc.R, R/seurat.R \name{DefaultAssay} \alias{DefaultAssay} \alias{DefaultAssay<-} \alias{DefaultAssay.Graph} \alias{DefaultAssay<-.Graph} \alias{DefaultAssay.Assay} \alias{DefaultAssay<-.Assay} \alias{DefaultAssay.Assay5} \alias{DefaultAssay<-.Assay5} \alias{DefaultAssay.SeuratCommand} \alias{DefaultAssay.DimReduc} \alias{DefaultAssay<-.DimReduc} \alias{DefaultAssay.Seurat} \alias{DefaultAssay<-.Seurat} \title{Default Assay} \usage{ DefaultAssay(object, ...) DefaultAssay(object, ...) <- value \method{DefaultAssay}{Graph}(object, ...) \method{DefaultAssay}{Graph}(object, ...) <- value \method{DefaultAssay}{Assay}(object, ...) \method{DefaultAssay}{Assay}(object, ...) <- value \method{DefaultAssay}{Assay5}(object, ...) \method{DefaultAssay}{Assay5}(object, ...) <- value \method{DefaultAssay}{SeuratCommand}(object, ...) \method{DefaultAssay}{DimReduc}(object, ...) \method{DefaultAssay}{DimReduc}(object, ...) <- value \method{DefaultAssay}{Seurat}(object, ...) \method{DefaultAssay}{Seurat}(object, ...) <- value } \arguments{ \item{object}{An object} \item{...}{Arguments passed to other methods} \item{value}{Name of assay to set as default} } \value{ \code{DefaultAssay}: The name of the default assay \code{DefaultAssay<-}: An object with the default assay updated } \description{ Get and set the default assay } \examples{ # Get current default assay DefaultAssay(object = pbmc_small) # Create dummy new assay to demo switching default assays new.assay <- pbmc_small[["RNA"]] Key(object = new.assay) <- "RNA2_" pbmc_small[["RNA2"]] <- new.assay # switch default assay to RNA2 DefaultAssay(object = pbmc_small) <- "RNA2" DefaultAssay(object = pbmc_small) } \concept{data-access} SeuratObject/man/dot-MARGIN.Rd0000644000176200001440000000053314520004144015442 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R \name{.MARGIN} \alias{.MARGIN} \title{Get the Margin of an Object} \usage{ .MARGIN(x, ...) } \arguments{ \item{x}{An object} } \value{ The margin, eg. \code{1} for rows or \code{2} for columns } \description{ Get the Margin of an Object } \keyword{internal} SeuratObject/man/dot-Collections.Rd0000644000176200001440000000136214520004144016744 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{.Collections} \alias{.Collections} \title{Identify Object Collections} \usage{ .Collections(object, exclude = character(length = 0L), ...) } \arguments{ \item{object}{An \link[methods:Classes_Details]{S4} object} \item{exclude}{A character vector of slot names to exclude} \item{...}{Arguments passed to \code{\link{IsNamedList}}} } \value{ A character vector of names of collection slots } \description{ Find all collection (named lists) slots in an S4 object } \examples{ .Collections(pbmc_small) } \seealso{ \code{\link{.FilterObjects}()}, \code{\link{.FindObject}()}, \code{\link{.Subobjects}()} } \concept{subobjects} \concept{utils} \keyword{internal} SeuratObject/man/dim.Assay.Rd0000644000176200001440000000143114520004144015527 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay.R \name{dim.Assay} \alias{dim.Assay} \title{Feature and Cell Numbers} \usage{ \method{dim}{Assay}(x) } \arguments{ \item{x}{An \code{\link{Assay}} object} } \value{ A two-length numeric vector with the total number of features and cells in \code{x} } \description{ Feature and Cell Numbers } \examples{ rna <- pbmc_small[["RNA"]] dim(rna) } \seealso{ v3 Assay object, validity, and interaction methods: \code{\link{$.Assay}()}, \code{\link{Assay-class}}, \code{\link{Assay-validity}}, \code{\link{CreateAssayObject}()}, \code{\link{[.Assay}()}, \code{\link{[[.Assay}()}, \code{\link{dimnames.Assay}()}, \code{\link{merge.Assay}()}, \code{\link{split.Assay}()}, \code{\link{subset.Assay}()} } \concept{assay} SeuratObject/man/show-SeuratCommand-method.Rd0000644000176200001440000000074314520004144020702 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/command.R \name{show,SeuratCommand-method} \alias{show,SeuratCommand-method} \title{Command Log Overview} \usage{ \S4method{show}{SeuratCommand}(object) } \value{ Prints summary to \code{\link[base]{stdout}} and invisibly returns \code{NULL} } \description{ Overview of a \code{\link{SeuratCommand}} object } \examples{ cmd <- pbmc_small[["NormalizeData.RNA"]] cmd } \concept{command} \keyword{internal} SeuratObject/man/dot-FindObject.Rd0000644000176200001440000000142714520004144016477 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{.FindObject} \alias{.FindObject} \title{Find A Subobject} \usage{ .FindObject(object, name, exclude = c("misc", "tools")) } \arguments{ \item{object}{An \link[methods:Classes_Details]{S4} object} \item{name}{Name of subobject to find} \item{exclude}{A character vector of slot names to exclude} } \value{ The name of the slot that contains \code{name}; returns \code{NULL} if a subobject named \code{name} cannot be found } \description{ Determine the slot that a subobject is contained in } \examples{ .FindObject(pbmc_small, "tsne") } \seealso{ \code{\link{.Collections}()}, \code{\link{.FilterObjects}()}, \code{\link{.Subobjects}()} } \concept{subobjects} \concept{utils} \keyword{internal} SeuratObject/man/SplitLayers.Rd0000644000176200001440000000137014520004201016146 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/assay5.R, R/seurat.R \name{JoinLayers} \alias{JoinLayers} \alias{JoinLayers.Assay5} \alias{JoinLayers.Seurat} \title{Split and Join Layers Together} \usage{ JoinLayers(object, ...) \method{JoinLayers}{Assay5}(object, layers = NULL, new = NULL, ...) \method{JoinLayers}{Seurat}(object, assay = NULL, layers = NULL, new = NULL, ...) } \arguments{ \item{object}{An object} \item{...}{Arguments passed to other methods} \item{layers}{Names of layers to split or join} \item{new}{Name of new layers} \item{assay}{Name of assay to split layers} } \value{ \code{object} with the layers specified joined } \description{ Split and Join Layers Together } \concept{assay5} SeuratObject/man/dot-Contains.Rd0000644000176200001440000000065514520004144016250 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{.Contains} \alias{.Contains} \title{Get Parent S4 Classes} \usage{ .Contains(object) } \arguments{ \item{object}{An \link[methods:Classes_Details]{S4} object} } \value{ A vector of class names that \code{object} inherits from } \description{ Get Parent S4 Classes } \examples{ .Contains(pbmc_small) } \concept{utils} \keyword{internal} SeuratObject/man/merge.StdAssay.Rd0000644000176200001440000000220514520004144016530 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay5.R \name{merge.StdAssay} \alias{merge.StdAssay} \title{Merge Assays} \usage{ \method{merge}{StdAssay}(x, y, labels = NULL, add.cell.ids = NULL, collapse = FALSE, ...) } \arguments{ \item{x}{An \code{\link{Assay5}} object} \item{y}{One or more \code{\link{Assay5}} objects} \item{labels}{A character vector equal to the number of objects; defaults to \code{as.character(seq_along(c(x, y)))}} \item{add.cell.ids}{A character vector equal to the number of objects provided to append to all cell names; if \code{TRUE}, uses \code{labels} as \code{add.cell.ids}} \item{collapse}{If \code{TRUE}, merge layers of the same name together; if \code{FALSE}, appends \code{labels} to the layer name} \item{...}{Ignored} } \value{ A new v5 assay with data merged from \code{c(x, y)} } \description{ Merge one or more v5 assays together } \details{ \strong{Note}: collapsing layers is currently not supported } \note{ All assays must be of the same type; merging different v5 assays (eg. \code{\link{Assay5}} and \code{\link{Assay5T}}) is currently unsupported } \keyword{internal} SeuratObject/man/pbmc_small.Rd0000644000176200001440000000226714473173564016044 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/data.R \docType{data} \name{pbmc_small} \alias{pbmc_small} \title{A small example version of the PBMC dataset} \format{ A Seurat object with the following slots filled \describe{ \item{assays}{ \itemize{Currently only contains one assay ("RNA" - scRNA-seq expression data) \item{counts - Raw expression data} \item{data - Normalized expression data} \item{scale.data - Scaled expression data} \item{var.features - names of the current features selected as variable} \item{meta.features - Assay level metadata such as mean and variance} }} \item{meta.data}{Cell level metadata} \item{active.assay}{Current default assay} \item{active.ident}{Current default idents} \item{graphs}{Neighbor graphs computed, currently stores the SNN} \item{reductions}{Dimensional reductions: currently PCA and tSNE} \item{version}{Seurat version used to create the object} \item{commands}{Command history} } } \source{ \url{https://support.10xgenomics.com/single-cell-gene-expression/datasets/1.1.0/pbmc3k} } \usage{ pbmc_small } \description{ A subsetted version of 10X Genomics' 3k PBMC dataset } \keyword{datasets} SeuratObject/man/DimReduc-class.Rd0000644000176200001440000000325614520004144016505 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/dimreduc.R \docType{class} \name{DimReduc-class} \alias{DimReduc-class} \alias{DimReduc} \title{The Dimensional Reduction Class} \description{ The DimReduc object stores a dimensionality reduction taken out in Seurat; each DimReduc consists of a cell embeddings matrix, a feature loadings matrix, and a projected feature loadings matrix. } \section{Slots}{ \describe{ \item{\code{cell.embeddings}}{Cell embeddings matrix (required)} \item{\code{feature.loadings}}{Feature loadings matrix (optional)} \item{\code{feature.loadings.projected}}{Projected feature loadings matrix (optional)} \item{\code{assay.used}}{Name of assay used to generate \code{DimReduc} object} \item{\code{global}}{Is this \code{DimReduc} global/persistent? If so, it will not be removed when removing its associated assay} \item{\code{stdev}}{A vector of standard deviations} \item{\code{jackstraw}}{A \code{\link{JackStrawData-class}} object associated with this \code{DimReduc}} \item{\code{misc}}{A named list of unstructured miscellaneous data} \item{\code{key}}{A one-length character vector with the object's key; keys must be one or more alphanumeric characters followed by an underscore \dQuote{\code{_}} (regex pattern \dQuote{\code{\Sexpr[stage=build]{SeuratObject:::.KeyPattern()}}})} }} \seealso{ Dimensional reduction object, validity, and interaction methods \code{\link{CreateDimReducObject}()}, \code{\link{DimReduc-validity}}, \code{\link{[.DimReduc}()}, \code{\link{[[.DimReduc}()}, \code{\link{dim.DimReduc}()}, \code{\link{merge.DimReduc}()}, \code{\link{print.DimReduc}()}, \code{\link{subset.DimReduc}()} } \concept{dimreduc} SeuratObject/man/FOV-methods.Rd0000644000176200001440000001300614520004201015765 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/fov.R \name{FOV-methods} \alias{FOV-methods} \alias{Cells.FOV} \alias{Features.FOV} \alias{FetchData.FOV} \alias{GetTissueCoordinates.FOV} \alias{Keys.FOV} \alias{RenameCells.FOV} \alias{$.FOV} \alias{[.FOV} \alias{[[.FOV} \alias{length.FOV} \alias{names.FOV} \alias{subset.FOV} \alias{[[<-,FOV,character,missing,Centroids-method} \alias{[[<-,FOV,character,missing,Molecules-method} \alias{[[<-,FOV,character,missing,NULL-method} \alias{[[<-,FOV,character,missing,Segmentation-method} \alias{show,FOV-method} \title{\code{FOV} Methods} \usage{ \method{Cells}{FOV}(x, boundary = NULL, ...) \method{Features}{FOV}(x, set = NULL, ...) \method{FetchData}{FOV}(object, vars, cells = NULL, simplify = TRUE, ...) \method{GetTissueCoordinates}{FOV}(object, which = NULL, ...) \method{Keys}{FOV}(object, ...) \method{RenameCells}{FOV}(object, new.names = NULL, ...) \method{$}{FOV}(x, i, ...) \method{[}{FOV}(x, i, j, ...) \method{[[}{FOV}(x, i, ...) \method{length}{FOV}(x) \method{names}{FOV}(x) \method{subset}{FOV}(x, cells = NULL, features = NULL, ...) \S4method{[[}{FOV,character,missing,Centroids}(x, i, j, ...) <- value \S4method{[[}{FOV,character,missing,Molecules}(x, i, j, ...) <- value \S4method{[[}{FOV,character,missing,`NULL`}(x, i, j, ...) <- value \S4method{[[}{FOV,character,missing,Segmentation}(x, i, j, ...) <- value \S4method{show}{FOV}(object) } \arguments{ \item{x, object}{A \code{\link{FOV}} object} \item{boundary, set}{Name of segmentation boundary or molecule set to extract cell or feature names for; pass \code{NA} to return all cells or feature names} \item{...}{Arguments passed to other methods} \item{vars}{A vector of variables to fetch; can be the name of a segmentation boundary, to get tissue coordinates, or molecule names, to get molecule coordinates} \item{simplify}{If only returning either boundary or molecule coordinates, return a single data frame instead of a list} \item{which}{Name of segmentation boundary or molecule set} \item{new.names}{vector of new cell names} \item{i, cells}{For \code{[[} and \code{[[<-}, the name of a segmentation or \dQuote{molecules}; for \code{FetchData}, \code{subset}. and \code{[}, a vector of cells to keep} \item{j, features}{For \code{subset} and \code{[}, a vector of features to keep; for \code{[[<-}, not used} \item{value}{For \code{[[<-}, a replacement \code{\link[SeuratObject:Molecules-class]{Molecules}}, \code{\link[SeuratObject:Centroids-class]{Centroids}}, or \code{\link[SeuratObject:Segmentation-class]{Segmentation}} object; otherwise \code{NULL} to remove the boundary stored at \code{i}} } \value{ \code{Cells}: A vector of cell names \code{Features}: A vector of spatially-resolved molecule names; if no molecular information present, returns \code{NULL} \code{FetchData}: If both molecule and boundary coordinates are requested, then a two-length list: \itemize{ \item \dQuote{\code{molecules}}: A data frame with the molecule coordinates requested. If molecules requested are keyed, the keys are preserved in the data frame \item \dQuote{\code{coordinates}}: A data frame with coordinates from the segmentation boundaries requested } If \code{simplify} is \code{TRUE} and only one data frame is generated, then only the data frame is returned. Otherwise, a one-length list is returned with the single data frame generated \code{GetTissueCoordinates}: ... \code{Keys}: A named vector of molecule set keys; names are the names of the molecule sets and values are the keys for the respective molecule set \code{RenameCells}: \code{object} with the cells renamed to \code{new.names} \code{$}, \code{[[}: The segmentation boundary or spatially-resolved molecule information stored at \code{i} \code{length}: The number of segmentation layers (\code{\link[SeuratObject:Segmentation-class]{Segmentation}} or \code{\link[SeuratObject:Centroids-class]{Centroids}} objects) \code{names}: A vector of segmentation boundary and molecule set names \code{subset}: \code{x} with just the cells and features specified \code{[[<-}: Varies depending on the class of \code{value}: \itemize{ \item If \code{value} is \code{NULL}, returns \code{x} with the boundary \code{i} removed; also allows removing \code{molecules}; does not allow removing the default segmentation \item If \code{value} is a \code{Molecules}, returns \code{x} with \code{value} stored in \code{molecules}; requires that \code{i} is \dQuote{molecules} \item Otherwise, stores \code{value} as a segmentation boundary named \code{i} } \code{show}: Invisibly returns \code{NULL} } \description{ Methods for \code{\link{FOV}} objects } \details{ The following methods are defined for interacting with a \code{FOV} object: \code{Cells}: Get cell names \code{Features}: Get spatially-resolved molecule names \code{FetchData}: Fetch boundary and/or molecule coordinates from a \code{FOV} object \code{GetTissueCoordinates}: Get boundary or molecule coordinates from a \code{FOV} object \code{Keys}: Get the keys of molecule sets contained within a \code{FOV} object \code{RenameCells}: Update cell names \code{$}, \code{[[}: Extract a segmentation boundary \code{length}: Get the number of segmentation layers in a \code{FOV} object \code{names}: Get the names of segmentation layers and molecule sets \code{subset}, \code{[}: Subset a \code{FOV} object \code{[[<-}: Add or remove segmentation layers and molecule information to/from a \code{FOV} object \code{show}: Display an object summary to stdout } \seealso{ \code{\link{FOV-class}} } \concept{fov} SeuratObject/man/Assay-validity.Rd0000644000176200001440000000267614520004144016616 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay.R \name{Assay-validity} \alias{Assay-validity} \title{V3 Assay Validity} \description{ Validation of \code{Assay} objects is handled by \code{\link[methods]{validObject}} } \section{\code{data} Validation}{ blah } \section{\code{counts} Validation}{ blah } \section{\code{scale.data} Validation}{ blah } \section{Feature-Level Meta Data Validation}{ blah } \section{Variable Feature Validation}{ blah } \section{Key Validation}{ Keys must be a one-length character vector; a key must be composed of one of the following: \itemize{ \item An empty string (eg. \dQuote{\code{''}}) where \code{nzchar() == 0} \item An string composed of one or more alphanumeric values (both lower- and upper-case) that ends with an underscore (\dQuote{\code{_}}); the first character must be a letter } Keys that are not empty strings are validated with the regex \dQuote{\code{\Sexpr[stage=build]{SeuratObject:::.KeyPattern()}}} } \examples{ rna <- pbmc_small[["RNA"]] validObject(rna) } \seealso{ \code{\link[methods]{validObject}} v3 Assay object, validity, and interaction methods: \code{\link{$.Assay}()}, \code{\link{Assay-class}}, \code{\link{CreateAssayObject}()}, \code{\link{[.Assay}()}, \code{\link{[[.Assay}()}, \code{\link{dim.Assay}()}, \code{\link{dimnames.Assay}()}, \code{\link{merge.Assay}()}, \code{\link{split.Assay}()}, \code{\link{subset.Assay}()} } \concept{assay} SeuratObject/man/Theta.Rd0000644000176200001440000000040714520004201014740 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R \name{Theta} \alias{Theta} \title{Get the offset angle} \usage{ Theta(object) } \arguments{ \item{object}{An object} } \description{ Get the offset angle } \concept{spatial} SeuratObject/man/Centroids-methods.Rd0000644000176200001440000000660214520004201017271 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/centroids.R \name{Centroids-methods} \alias{Centroids-methods} \alias{Cells.Centroids} \alias{GetTissueCoordinates.Centroids} \alias{Radius.Centroids} \alias{RenameCells.Centroids} \alias{Theta.Centroids} \alias{is.finite.Centroids} \alias{is.infinite.Centroids} \alias{length.Centroids} \alias{lengths.Centroids} \alias{subset.Centroids} \alias{[,Centroids,character,ANY,ANY-method} \alias{[,Centroids,numeric,ANY,ANY-method} \alias{show,Centroids-method} \title{\code{Centroids} Methods} \usage{ \method{Cells}{Centroids}(x, ...) \method{GetTissueCoordinates}{Centroids}(object, full = TRUE, ...) \method{Radius}{Centroids}(object) \method{RenameCells}{Centroids}(object, new.names = NULL, ...) \method{Theta}{Centroids}(object) \method{is.finite}{Centroids}(x) \method{is.infinite}{Centroids}(...) \method{length}{Centroids}(x) \method{lengths}{Centroids}(x, use.names = TRUE) \method{subset}{Centroids}(x, cells = NULL, ...) \S4method{[}{Centroids,character,ANY,ANY}(x, i, j, ..., drop = TRUE) \S4method{[}{Centroids,numeric,ANY,ANY}(x, i, j, ..., drop = TRUE) \S4method{show}{Centroids}(object) } \arguments{ \item{x, object}{A \code{\link[SeuratObject:Centroids-class]{Centroids}} object} \item{...}{Arguments passed to other methods} \item{full}{Expand the coordinates to the full polygon} \item{new.names}{vector of new cell names} \item{use.names}{Ignored} \item{i, cells}{A vector of cells to keep; if \code{NULL}, defaults to all cells} \item{j, drop}{Ignored} } \value{ \code{GetTissueCoordinates}: A data frame with three columns: \itemize{ \item \dQuote{\code{x}}: the x-coordinate \item \dQuote{\code{y}}: the y-coordinate \item \dQuote{\code{cell}}: the cell name } If \code{full} is \code{TRUE}, then each coordinate will indicate a vertex for the cell polygon; otherwise, each coordinate will indicate a centroid for the cell \code{Radius} The radius of the centroids \code{RenameCells}: \code{object} with the cells renamed to \code{new.names} \code{Theta}: The offset angle in degrees \code{is.finite}: \code{TRUE} if the centroids are polygonal, \code{FALSE} if circular \code{is.infinite}: The opposite of \code{is.finite} \code{length}: \code{0} if the centroids are circular, otherwise the number of sides of the polygonal centroid \code{lengths}: An \code{\link[base:rle]{rle}} object for the cells \code{subset}, \code{[}: \code{x} subsetted to the cells specified by \code{cells}/\code{i} \code{show}: Invisibly returns \code{NULL} } \description{ Methods for \code{\link[SeuratObject:Centroids-class]{Centroids}} objects } \details{ \code{GetTissueCoordinates}: Get cell spatial coordinates \code{Radius}: Get the centroid radius \code{RenameCells}: Update cell names \code{Theta}: Get the offset angle \code{is.finite}, \code{is.infinite}: Test to see if the centroids are circular or polygonal \code{length}: Get the number of sides for the polygonal centroid \code{lengths}: Generate a run-length encoding of the cells present \code{subset}, \code{[}: Subset a \code{Centroids} object to certain cells \code{show}: Display an object summary to stdout } \seealso{ \code{\link{Centroids-class}} Segmentation layer classes: \code{\link{Centroids-class}}, \code{\link{Molecules-class}}, \code{\link{Molecules-methods}}, \code{\link{Segmentation-class}}, \code{\link{Segmentation-methods}} } \concept{segmentation} SeuratObject/man/CreateAssayObject.Rd0000644000176200001440000000333314520004144017235 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay.R \name{CreateAssayObject} \alias{CreateAssayObject} \title{Create an Assay object} \usage{ CreateAssayObject( counts, data, min.cells = 0, min.features = 0, key = NULL, check.matrix = FALSE, ... ) } \arguments{ \item{counts}{Unnormalized data such as raw counts or TPMs} \item{data}{Prenormalized data; if provided, do not pass \code{counts}} \item{min.cells}{Include features detected in at least this many cells. Will subset the counts matrix as well. To reintroduce excluded features, create a new object with a lower cutoff} \item{min.features}{Include cells where at least this many features are detected} \item{key}{Optional key to initialize assay with} \item{check.matrix}{Check counts matrix for NA, NaN, Inf, and non-integer values} \item{...}{Arguments passed to \code{\link{as.sparse}}} } \value{ A \code{\link{Assay}} object } \description{ Create an Assay object from a feature (e.g. gene) expression matrix. The expected format of the input matrix is features x cells. } \details{ Non-unique cell or feature names are not allowed. Please make unique before calling this function. } \examples{ \dontrun{ pbmc_raw <- read.table( file = system.file('extdata', 'pbmc_raw.txt', package = 'Seurat'), as.is = TRUE ) pbmc_rna <- CreateAssayObject(counts = pbmc_raw) pbmc_rna } } \seealso{ v3 Assay object, validity, and interaction methods: \code{\link{$.Assay}()}, \code{\link{Assay-class}}, \code{\link{Assay-validity}}, \code{\link{[.Assay}()}, \code{\link{[[.Assay}()}, \code{\link{dim.Assay}()}, \code{\link{dimnames.Assay}()}, \code{\link{merge.Assay}()}, \code{\link{split.Assay}()}, \code{\link{subset.Assay}()} } \concept{assay} SeuratObject/man/CreateMolecules.Rd0000644000176200001440000000174214520004201016752 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/molecules.R \name{CreateMolecules} \alias{CreateMolecules} \alias{CreateMolecules.data.frame} \alias{CreateMolecules.Molecules} \alias{CreateMolecules.NULL} \title{Create a \code{\link{Molecules}} Object} \usage{ CreateMolecules(coords, ...) \method{CreateMolecules}{data.frame}(coords, key = "", ...) \method{CreateMolecules}{Molecules}(coords, ...) \method{CreateMolecules}{`NULL`}(coords, ...) } \arguments{ \item{coords}{Spatial coordinates for molecules; should be a data frame with three columns: \itemize{ \item \dQuote{\code{x}}: x-coordinates for each molecule \item \dQuote{\code{y}}: y-coordinates for each molecule \item \dQuote{\code{gene}}: gene name for each molecule }} \item{...}{Arguments passed to other methods} \item{key}{A key to set for the molecules} } \value{ A \code{\link{Molecules}} object } \description{ Create a \code{\link{Molecules}} Object } \concept{spatial} SeuratObject/man/DefaultFOV.Rd0000644000176200001440000000170314520004201015632 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/seurat.R \name{DefaultFOV} \alias{DefaultFOV} \alias{DefaultFOV<-} \alias{DefaultFOV.Seurat} \alias{DefaultFOV<-.Seurat} \title{Get and Set the Default FOV} \usage{ DefaultFOV(object, ...) DefaultFOV(object, ...) <- value \method{DefaultFOV}{Seurat}(object, assay = NULL, ...) \method{DefaultFOV}{Seurat}(object, assay = NA, ...) <- value } \arguments{ \item{object}{A \code{\link{Seurat}} Object} \item{...}{Arguments passed to other methods} \item{value}{The name of the \code{\link{FOV}} to set as the default} \item{assay}{Name of assay to get or set default \code{\link{FOV}} for; pass \code{NA} to get or set the global default \code{\link{FOV}}} } \value{ \code{DefaultFOV}: The name of the default \code{\link{FOV}} \code{DefaultFOV<-}: \code{object} with the default FOV set to \code{value} } \description{ Get and Set the Default FOV } \concept{spatial} SeuratObject/man/merge.Seurat.Rd0000644000176200001440000000626414520004144016251 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/seurat.R \name{merge.Seurat} \alias{merge.Seurat} \alias{merge} \alias{MergeSeurat} \alias{AddSamples} \title{Merge Seurat Objects} \usage{ \method{merge}{Seurat}( x = NULL, y = NULL, add.cell.ids = NULL, collapse = FALSE, merge.data = TRUE, merge.dr = FALSE, project = getOption(x = "Seurat.object.project", default = "SeuratProject"), ... ) } \arguments{ \item{x}{A \code{\link{Seurat}} object} \item{y}{A single \code{Seurat} object or a list of \code{Seurat} objects} \item{add.cell.ids}{A character vector of \code{length(x = c(x, y))}; appends the corresponding values to the start of each objects' cell names} \item{collapse}{If \code{TRUE}, merge layers of the same name together; if \code{FALSE}, appends \code{labels} to the layer name} \item{merge.data}{Merge the data slots instead of just merging the counts (which requires renormalization); this is recommended if the same normalization approach was applied to all objects} \item{merge.dr}{Choose how to handle merging dimensional reductions: \itemize{ \item \dQuote{\code{TRUE}}: merge dimensional reductions with the same name across objects; dimensional reductions with different names are added as-is \item \dQuote{\code{NA}}: keep dimensional reductions from separate objects separate; will append the project name for duplicate reduction names \item \dQuote{\code{FALSE}}: do not add dimensional reductions }} \item{project}{\link{Project} name for the \code{Seurat} object} \item{...}{Arguments passed to other methods} } \value{ \code{merge}: Merged object } \description{ Merge Seurat Objects } \section{Merge Details}{ When merging Seurat objects, the merge procedure will merge the Assay level counts and potentially the data slots (depending on the merge.data parameter). It will also merge the cell-level meta data that was stored with each object and preserve the cell identities that were active in the objects pre-merge. The merge will optionally merge reductions depending on the values passed to \code{merge.dr} if they have the same name across objects. Here the embeddings slots will be merged and if there are differing numbers of dimensions across objects, only the first N shared dimensions will be merged. The feature loadings slots will be filled by the values present in the first object.The merge will not preserve graphs, logged commands, or feature-level metadata that were present in the original objects. If add.cell.ids isn't specified and any cell names are duplicated, cell names will be appended with _X, where X is the numeric index of the object in c(x, y). } \examples{ # `merge' examples # merge two objects merge(pbmc_small, y = pbmc_small) # to merge more than two objects, pass one to x and a list of objects to y merge(pbmc_small, y = c(pbmc_small, pbmc_small)) } \seealso{ Seurat object, validity, and interaction methods \code{\link{$.Seurat}()}, \code{\link{Seurat-class}}, \code{\link{Seurat-validity}}, \code{\link{[[.Seurat}()}, \code{\link{[[<-,Seurat,NULL}}, \code{\link{[[<-,Seurat}}, \code{\link{dim.Seurat}()}, \code{\link{dimnames.Seurat}()}, \code{\link{names.Seurat}()}, \code{\link{subset.Seurat}()} } \concept{seurat} SeuratObject/man/Key.Rd0000644000176200001440000000272614520004144014437 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/assay.R, R/assay5.R, % R/dimreduc.R, R/seurat.R \name{Key} \alias{Key} \alias{Keys} \alias{Key<-} \alias{Key.Assay} \alias{Key<-.Assay} \alias{Key.Assay5} \alias{Key<-.Assay5} \alias{Key.DimReduc} \alias{Key<-.DimReduc} \alias{Key.Seurat} \alias{Keys.Seurat} \title{Get and set object keys} \usage{ Key(object, ...) Keys(object, ...) Key(object, ...) <- value \method{Key}{Assay}(object, ...) \method{Key}{Assay}(object, ...) <- value \method{Key}{Assay5}(object, ...) \method{Key}{Assay5}(object, ...) <- value \method{Key}{DimReduc}(object, ...) \method{Key}{DimReduc}(object, ...) <- value \method{Key}{Seurat}(object, ...) \method{Keys}{Seurat}(object, ...) } \arguments{ \item{object}{An object} \item{...}{Arguments passed to other methods} \item{value}{Key value} } \value{ \code{Key}: the object key \code{Keys}: a named vector of keys of sub-objects \code{Key<-}: \code{object} with an updated key } \description{ Get and set object keys } \examples{ # Get an Assay key Key(pbmc_small[["RNA"]]) # Set the key for an Assay Key(pbmc_small[["RNA"]]) <- "newkey_" Key(pbmc_small[["RNA"]]) # Get a DimReduc key Key(object = pbmc_small[["pca"]]) # Set the key for DimReduc Key(object = pbmc_small[["pca"]]) <- "newkey2_" Key(object = pbmc_small[["pca"]]) # Show all keys associated with a Seurat object Key(object = pbmc_small) Keys(object = pbmc_small) } \concept{data-access} SeuratObject/man/angles.Rd0000644000176200001440000000106514520004144015153 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{Angles} \alias{Angles} \alias{Degrees} \alias{Radians} \title{Radian/Degree Conversions} \usage{ Degrees(rad) Radians(deg) } \arguments{ \item{rad}{Angle in radians} \item{deg}{Angle in degrees} } \value{ \code{Degrees}: \code{rad} in degrees \code{Radians}: \code{deg} in radians } \description{ Convert degrees to radians and vice versa } \examples{ Degrees(pi) Radians(180) } \seealso{ \code{\link{PolyVtx}()} } \concept{angles} \concept{utils} \keyword{internal} SeuratObject/man/RowMergeSparseMatrices.Rd0000644000176200001440000000113614473173564020322 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{RowMergeSparseMatrices} \alias{RowMergeSparseMatrices} \title{Merge Sparse Matrices by Row} \usage{ RowMergeSparseMatrices(mat1, mat2) } \arguments{ \item{mat1}{First matrix} \item{mat2}{Second matrix or list of matrices} } \value{ Returns a sparse matrix } \description{ Merge two or more sparse matrices by rowname. } \details{ Shared matrix rows (with the same row name) will be merged, and unshared rows (with different names) will be filled with zeros in the matrix not containing the row. } \concept{utils} SeuratObject/man/EmptyDF.Rd0000644000176200001440000000072414520004144015213 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{EmptyDF} \alias{EmptyDF} \title{Empty Data Frames} \usage{ EmptyDF(n) } \arguments{ \item{n}{Number of rows for the data frame} } \value{ A \link[base:data.frame]{data frame} with \code{n} rows and zero columns } \description{ Create an empty \link[base:data.frame]{data frame} with no row names and zero columns } \examples{ EmptyDF(4L) } \concept{utils} \keyword{internal} SeuratObject/man/StdAssay-validity.Rd0000644000176200001440000000240414520004144017256 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay5.R \name{StdAssay-validity} \alias{StdAssay-validity} \title{V5 Assay Validity} \description{ Validation of \code{StdAssay} objects is handled by \code{\link[methods]{validObject}} } \section{Layer Validation}{ blah } \section{Key Validation}{ Keys must be a one-length character vector; a key must be composed of one of the following: \itemize{ \item An empty string (eg. \dQuote{\code{''}}) where \code{nzchar() == 0} \item An string composed of one or more alphanumeric values (both lower- and upper-case) that ends with an underscore (\dQuote{\code{_}}); the first character must be a letter } Keys that are not empty strings are validated with the regex \dQuote{\code{\Sexpr[stage=build]{SeuratObject:::.KeyPattern()}}} } \seealso{ \code{\link[methods]{validObject}} v5 Standard Assay object, validity, and interaction methods \code{\link{$.StdAssay}()}, \code{\link{.DollarNames.StdAssay}()}, \code{\link{StdAssay-class}}, \code{\link{[.StdAssay}()}, \code{\link{[[.StdAssay}()}, \code{\link{dim.StdAssay}()}, \code{\link{dimnames.StdAssay}()}, \code{\link{show,StdAssay-method}}, \code{\link{split.StdAssay}()}, \code{\link{subset.StdAssay}()} } \concept{stdassay} \keyword{internal} SeuratObject/man/dot-SelectFeatures.Rd0000644000176200001440000000101314520004144017375 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/utils.R \name{.SelectFeatures} \alias{.SelectFeatures} \alias{.SelectFeatures.list} \title{Combine and Select Features} \usage{ .SelectFeatures(object, ...) \method{.SelectFeatures}{list}(object, all.features = NULL, nfeatures = Inf, ...) } \arguments{ \item{object}{An object} \item{...}{Arguments passed to other methods} } \value{ A vector of features selected } \description{ Combine and Select Features } \keyword{internal} SeuratObject/man/Neighbor-class.Rd0000644000176200001440000000147314473173564016571 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/neighbor.R \docType{class} \name{Neighbor-class} \alias{Neighbor-class} \alias{Neighbor} \title{The Neighbor class} \description{ The Neighbor class is used to store the results of neighbor finding algorithms } \section{Slots}{ \describe{ \item{\code{nn.idx}}{Matrix containing the nearest neighbor indices} \item{\code{nn.dist}}{Matrix containing the nearest neighbor distances} \item{\code{alg.idx}}{The neighbor finding index (if applicable). E.g. the annoy index} \item{\code{alg.info}}{Any information associated with the algorithm that may be needed downstream (e.g. distance metric used with annoy is needed when reading in from stored file).} \item{\code{cell.names}}{Names of the cells for which the neighbors have been computed.} }} SeuratObject/man/SeuratObject-package.Rd0000644000176200001440000000526614523024456017707 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/zzz.R \docType{package} \name{SeuratObject-package} \alias{SeuratObject} \alias{SeuratObject-package} \title{SeuratObject: Data Structures for Single Cell Data} \description{ Defines S4 classes for single-cell genomic data and associated information, such as dimensionality reduction embeddings, nearest-neighbor graphs, and spatially-resolved coordinates. Provides data access methods and R-native hooks to ensure the Seurat object is familiar to other R users. See Satija R, Farrell J, Gennert D, et al (2015) \doi{10.1038/nbt.3192}, Macosko E, Basu A, Satija R, et al (2015) \doi{10.1016/j.cell.2015.05.002}, and Stuart T, Butler A, et al (2019) \doi{10.1016/j.cell.2019.05.031}, Hao Y, Hao S, et al (2021) \doi{10.1016/j.cell.2021.04.048} and Hao Y, et al (2023) \doi{10.1101/2022.02.24.481684} for more details. } \seealso{ Useful links: \itemize{ \item \url{https://mojaveazure.github.io/seurat-object/} \item \url{https://github.com/mojaveazure/seurat-object} \item Report bugs at \url{https://github.com/mojaveazure/seurat-object/issues} } } \author{ \strong{Maintainer}: Paul Hoffman \email{seurat@nygenome.org} (\href{https://orcid.org/0000-0002-7693-8957}{ORCID}) Authors: \itemize{ \item Rahul Satija \email{rsatija@nygenome.org} (\href{https://orcid.org/0000-0001-9448-8833}{ORCID}) \item Yuhan Hao \email{yhao@nygenome.org} (\href{https://orcid.org/0000-0002-1810-0822}{ORCID}) \item Austin Hartman \email{ahartman@nygenome.org} (\href{https://orcid.org/0000-0001-7278-1852}{ORCID}) \item Gesmira Molla \email{gmolla@nygenome.org} (\href{https://orcid.org/0000-0002-8628-5056}{ORCID}) \item Andrew Butler \email{abutler@nygenome.org} (\href{https://orcid.org/0000-0003-3608-0463}{ORCID}) \item Tim Stuart \email{tstuart@nygenome.org} (\href{https://orcid.org/0000-0002-3044-0897}{ORCID}) } Other contributors: \itemize{ \item Madeline Kowalski \email{mkowalski@nygenome.org} (\href{https://orcid.org/0000-0002-5655-7620}{ORCID}) [contributor] \item Saket Choudhary \email{schoudhary@nygenome.org} (\href{https://orcid.org/0000-0001-5202-7633}{ORCID}) [contributor] \item Skylar Li \email{sli@nygenome.org} [contributor] \item Longda Jiang \email{ljiang@nygenome.org} (\href{https://orcid.org/0000-0003-4964-6497}{ORCID}) [contributor] \item Jeff Farrell \email{jfarrell@g.harvard.edu} [contributor] \item Shiwei Zheng \email{szheng@nygenome.org} (\href{https://orcid.org/0000-0001-6682-6743}{ORCID}) [contributor] \item Christoph Hafemeister \email{chafemeister@nygenome.org} (\href{https://orcid.org/0000-0001-6365-8254}{ORCID}) [contributor] \item Patrick Roelli \email{proelli@nygenome.org} [contributor] } } SeuratObject/man/sub-subset-Seurat-character-missing-StdAssay-method.Rd0000644000176200001440000000273614520004144025655 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/seurat.R \name{[[<-,Seurat,character,missing,StdAssay-method} \alias{[[<-,Seurat,character,missing,StdAssay-method} \title{Add Subobjects} \usage{ \S4method{[[}{Seurat,character,missing,StdAssay}(x, i, j, ...) <- value } \arguments{ \item{x}{A \code{\link{Seurat}} object} \item{i}{Name to add subobject as} \item{j}{Ignored} \item{...}{Ignored} \item{value}{A valid subobject (eg. a \link[=Assay]{v3} or \link[=Assay5]{v5} assay, or a \link[=DimReduc]{dimensional reduction})} } \value{ \code{x} with \code{value} added as \code{i} } \description{ Add subobjects containing expression, dimensional reduction, or other containerized data to a \code{\link{Seurat}} object. Subobjects can be accessed with \code{\link[=[[.Seurat]{[[}} and manipulated directly within the \code{Seurat} object or used independently } \seealso{ See \link[=[[.Seurat]{here} for pulling subobjects using \code{[[}, \link[=$.Seurat]{here} for adding metadata with \code{[[<-}, and \link[=[[<-,Seurat,NULL]{here} for removing subobjects and cell-level meta data with \code{[[<-} Seurat object, validity, and interaction methods \code{\link{$.Seurat}()}, \code{\link{Seurat-class}}, \code{\link{Seurat-validity}}, \code{\link{[[.Seurat}()}, \code{\link{[[<-,Seurat,NULL}}, \code{\link{dim.Seurat}()}, \code{\link{dimnames.Seurat}()}, \code{\link{merge.Seurat}()}, \code{\link{names.Seurat}()}, \code{\link{subset.Seurat}()} } \keyword{internal} SeuratObject/man/Layers-StdAssay.Rd0000644000176200001440000000345414520004144016676 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay5.R \name{Layers-StdAssay} \alias{Layers-StdAssay} \alias{LayerData.StdAssay} \alias{LayerData<-.StdAssay} \alias{Layers.StdAssay} \title{Query and Manipulate Assay Layers} \usage{ \method{LayerData}{StdAssay}( object, layer = NULL, cells = NULL, features = NULL, fast = FALSE, slot = deprecated(), ... ) \method{LayerData}{StdAssay}(object, layer, features = NULL, cells = NULL, ...) <- value \method{Layers}{StdAssay}(object, search = NA, ...) } \arguments{ \item{object}{An object} \item{layer}{Name of layer to fetch or set} \item{features, cells}{Vectors of features/cells to include} \item{fast}{Determine how to return the layer data; choose from: \describe{ \item{\code{FALSE}}{Apply any transpositions and attempt to add feature/cell names (if supported) back to the layer data} \item{\code{NA}}{Attempt to add feature/cell names back to the layer data, skip any transpositions} \item{\code{TRUE}}{Do not apply any transpositions or add feature/cell names to the layer data} }} \item{slot}{\Sexpr[stage=build,results=rd]{lifecycle::badge("deprecated")}} \item{...}{Arguments passed to other methods} \item{value}{New two-dimensional data to be added as a layer} \item{search}{A pattern to search layer names for; pass one of: \itemize{ \item \dQuote{\code{NA}} to pull all layers \item \dQuote{\code{NULL}} to pull the default layer(s) \item a \link[base:grep]{regular expression} that matches layer names }} } \value{ \code{LayerData}: the layer data for \code{layer} from \code{object} \code{Layer<-}: \code{object} with \code{value} added as a layer named \code{layer} \code{Layers}: the names of the layers present in \code{object} } \description{ Query and Manipulate Assay Layers } \keyword{internal} SeuratObject/man/split.StdAssay.Rd0000644000176200001440000000623614523024477016612 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay5.R \name{split.StdAssay} \alias{split.StdAssay} \alias{split,StdAssay-method} \title{Split an Assay} \usage{ \method{split}{StdAssay}( x, f, drop = FALSE, layers = c("counts", "data"), ret = c("assay", "multiassays", "layers"), ... ) \S4method{split}{StdAssay}( x, f, drop = FALSE, layers = c("counts", "data"), ret = c("assay", "multiassays", "layers"), ... ) } \arguments{ \item{x}{An \code{\link{Assay5}} object} \item{f}{a \sQuote{factor} in the sense that \code{\link[base]{as.factor}(f)} defines the grouping, or a list of such factors in which case their interaction is used for the grouping. If \code{x} is a data frame, \code{f} can also be a formula of the form \code{ ~ g} to split by the variable \code{g}, or more generally of the form \code{ ~ g1 + \dots + gk} to split by the interaction of the variables \code{g1}, \dots, \code{gk}, where these variables are evaluated in the data frame \code{x} using the usual non-standard evaluation rules.} \item{drop}{logical indicating if levels that do not occur should be dropped (if \code{f} is a \code{factor} or a list).} \item{layers}{Names of layers to include in the split; pass \code{NA} for all layers; pass \code{NULL} for the \link[=DefaultLayer]{default layer}} \item{ret}{Type of return value; choose from: \itemize{ \item \dQuote{\code{assay}}: a single \code{\link{Assay5}} object \item \dQuote{\code{multiassay}}: a list of \code{\link{Assay5}} objects \item \dQuote{\code{layers}}: a list of layer matrices }} \item{...}{Ignored} } \value{ Depends on the value of \code{ret}: \itemize{ \item \dQuote{\code{assay}}: \code{x} with the layers requested in \code{layers} split based on \code{f}; all other layers are left as-is \item \dQuote{\code{multiassay}}: a list of \code{\link{Assay5}} objects; the list contains one value per split and each assay contains only the layers requested in \code{layers} with the \link[=Key]{key} set to the split \item \dQuote{\code{layers}}: a list of matrices of length \code{length(assays) * length(unique(f))}; the list is named as \dQuote{\code{layer.split}} } } \description{ Split an Assay } \section{Progress Updates with \pkg{progressr}}{ This function uses \href{https://cran.r-project.org/package=progressr}{\pkg{progressr}} to render status updates and progress bars. To enable progress updates, wrap the function call in \code{\link[progressr]{with_progress}} or run \code{\link[progressr:handlers]{handlers(global = TRUE)}} before running this function. For more details about \pkg{progressr}, please read \href{https://progressr.futureverse.org/articles/progressr-intro.html}{\code{vignette("progressr-intro")}} } \seealso{ v5 Standard Assay object, validity, and interaction methods \code{\link{$.StdAssay}()}, \code{\link{.DollarNames.StdAssay}()}, \code{\link{StdAssay-class}}, \code{\link{StdAssay-validity}}, \code{\link{[.StdAssay}()}, \code{\link{[[.StdAssay}()}, \code{\link{dim.StdAssay}()}, \code{\link{dimnames.StdAssay}()}, \code{\link{show,StdAssay-method}}, \code{\link{subset.StdAssay}()} } \concept{stdassay} \keyword{internal} SeuratObject/man/FetchData.Rd0000644000176200001440000000324514520004144015527 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/dimreduc.R, R/seurat.R \name{FetchData} \alias{FetchData} \alias{FetchData.DimReduc} \alias{FetchData.Seurat} \title{Access cellular data} \usage{ FetchData(object, ...) \method{FetchData}{DimReduc}(object, vars, cells = NULL, ...) \method{FetchData}{Seurat}( object, vars, cells = NULL, layer = NULL, clean = TRUE, slot = deprecated(), ... ) } \arguments{ \item{object}{An object} \item{...}{Arguments passed to other methods} \item{vars}{List of all variables to fetch, use keyword \dQuote{ident} to pull identity classes} \item{cells}{Cells to collect data for (default is all cells)} \item{layer}{Layer to pull feature data for} \item{clean}{Remove cells that are missing data; choose from: \itemize{ \item \dQuote{\code{all}}: consider all columns for cleaning \item \dQuote{\code{ident}}: consider all columns except the identity class for cleaning \item \dQuote{\code{project}}: consider all columns except the identity class for cleaning; fill missing identity values with the object's project \item \dQuote{\code{none}}: do not clean } Passing \code{TRUE} is a shortcut for \dQuote{\code{ident}}; passing \code{FALSE} is a shortcut for \dQuote{\code{none}}} \item{slot}{Deprecated in favor of \code{layer}} } \value{ A data frame with cells as rows and cellular data as columns } \description{ Retrieves data (feature expression, PCA scores, metrics, etc.) for a set of cells in a Seurat object } \examples{ pc1 <- FetchData(object = pbmc_small, vars = 'PC_1') head(x = pc1) head(x = FetchData(object = pbmc_small, vars = c('groups', 'ident'))) } \concept{data-access} SeuratObject/man/cash-.Seurat.Rd0000644000176200001440000000400614520004144016135 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/seurat.R \name{$.Seurat} \alias{$.Seurat} \alias{$<-.Seurat} \alias{[[<-,Seurat,character,missing,data.frame-method} \alias{[[<-,Seurat,missing,missing,data.frame-method} \alias{[[<-,Seurat,character,missing,factor-method} \alias{[[<-,Seurat,character,missing,list-method} \alias{[[<-,Seurat,missing,missing,list-method} \alias{[[<-,Seurat,character,missing,vector-method} \title{Cell-Level Meta Data} \usage{ \method{$}{Seurat}(x, i) \method{$}{Seurat}(x, i, ...) <- value \S4method{[[}{Seurat,character,missing,data.frame}(x, i, j, ...) <- value \S4method{[[}{Seurat,missing,missing,data.frame}(x, i, j, ...) <- value \S4method{[[}{Seurat,character,missing,factor}(x, i, j, ...) <- value \S4method{[[}{Seurat,character,missing,list}(x, i, j, ...) <- value \S4method{[[}{Seurat,missing,missing,list}(x, i, j, ...) <- value \S4method{[[}{Seurat,character,missing,vector}(x, i, j, ...) <- value } \arguments{ \item{x}{A \code{\link{Seurat}} object} \item{i}{Name of cell-level meta data} \item{...}{Ignored} \item{value}{A vector to add as cell-level meta data} \item{j}{Ignored} } \value{ {$}: Metadata column \code{i} for object \code{x}; \strong{note}: unlike \code{[[}, \code{$} drops the shape of the metadata to return a vector instead of a data frame \code{$<-}: \code{x} with metadata \code{value} saved as \code{i} } \description{ Get and set cell-level meta data } \examples{ # Get metadata using `$' head(pbmc_small$groups) # Add metadata using the `$' operator set.seed(42) pbmc_small$value <- sample(1:3, size = ncol(pbmc_small), replace = TRUE) head(pbmc_small[["value"]]) } \seealso{ Seurat object, validity, and interaction methods \code{\link{Seurat-class}}, \code{\link{Seurat-validity}}, \code{\link{[[.Seurat}()}, \code{\link{[[<-,Seurat,NULL}}, \code{\link{[[<-,Seurat}}, \code{\link{dim.Seurat}()}, \code{\link{dimnames.Seurat}()}, \code{\link{merge.Seurat}()}, \code{\link{names.Seurat}()}, \code{\link{subset.Seurat}()} } \concept{seurat} SeuratObject/man/DefaultAssay-StdAssay.Rd0000644000176200001440000000123014520004144020012 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay5.R \name{DefaultAssay-StdAssay} \alias{DefaultAssay-StdAssay} \alias{DefaultAssay.StdAssay} \alias{DefaultAssay<-.StdAssay} \title{Default Assay} \usage{ \method{DefaultAssay}{StdAssay}(object, ...) \method{DefaultAssay}{StdAssay}(object, ...) <- value } \arguments{ \item{object}{An object} \item{...}{Arguments passed to other methods} \item{value}{Name of assay to set as default} } \value{ \code{DefaultAssay}: The name of the default assay \code{DefaultAssay<-}: An object with the default assay updated } \description{ Get and set the default assay } \keyword{internal} SeuratObject/man/CheckMatrix.Rd0000644000176200001440000000222314520004144016101 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/utils.R \name{CheckMatrix} \alias{CheckMatrix} \alias{CheckMatrix.default} \alias{CheckMatrix.dMatrix} \alias{CheckMatrix.lMatrix} \title{Check Matrix Validity} \usage{ CheckMatrix(object, checks, ...) \method{CheckMatrix}{default}(object, checks, ...) \method{CheckMatrix}{dMatrix}(object, checks = c("infinite", "logical", "integer", "na"), ...) \method{CheckMatrix}{lMatrix}(object, checks = c("infinite", "logical", "integer", "na"), ...) } \arguments{ \item{object}{A matrix} \item{checks}{Type of checks to perform, choose one or more from: \itemize{ \item \dQuote{\code{infinite}}: Emit a warning if any value is infinite \item \dQuote{\code{logical}}: Emit a warning if any value is a logical \item \dQuote{\code{integer}}: Emit a warning if any value is \emph{not} an integer \item \dQuote{\code{na}}: Emit a warning if any value is an \code{NA} or \code{NaN} }} \item{...}{Arguments passed to other methods} } \value{ Emits warnings for each test and invisibly returns \code{NULL} } \description{ Check Matrix Validity } \concept{utils} \keyword{internal} SeuratObject/man/FilterObjects.Rd0000644000176200001440000000147514520004144016446 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/seurat.R \name{FilterObjects} \alias{FilterObjects} \title{Find Sub-objects of a Certain Class} \usage{ FilterObjects(object, classes.keep = c("Assay", "StdAssay", "DimReduc")) } \arguments{ \item{object}{A \code{\link{Seurat}} object} \item{classes.keep}{A vector of names of classes to get} } \value{ A vector with the names of objects within the \code{Seurat} object that are of class \code{classes.keep} } \description{ Get the names of objects within a \code{Seurat} object that are of a certain class } \section{Lifecycle}{ \Sexpr[stage=build,results=rd]{lifecycle::badge("deprecated")} \code{FilterObjects} was deprecated in version 5.0.0; use \code{\link{.FilterObjects}} instead } \examples{ FilterObjects(pbmc_small) } \concept{utils} SeuratObject/man/Segmentation-class.Rd0000644000176200001440000000103114520004201017425 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/segmentation.R \docType{class} \name{Segmentation-class} \alias{Segmentation-class} \title{The \code{Segmentation} Class} \description{ The \code{Segmentation} Class } \seealso{ \code{Segmentation} methods: \code{\link{Segmentation-methods}} Segmentation layer classes: \code{\link{Centroids-class}}, \code{\link{Centroids-methods}}, \code{\link{Molecules-class}}, \code{\link{Molecules-methods}}, \code{\link{Segmentation-methods}} } \concept{segmentation} SeuratObject/man/MatchCells.Rd0000644000176200001440000000144114520004144015717 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/default.R \name{MatchCells} \alias{MatchCells} \alias{MatchCells.character} \alias{MatchCells.NULL} \alias{MatchCells.numeric} \title{Match Cells} \usage{ MatchCells(new, orig, ordered = FALSE) \method{MatchCells}{character}(new, orig, ordered = FALSE) \method{MatchCells}{`NULL`}(new, orig, ordered = FALSE) \method{MatchCells}{numeric}(new, orig, ordered = FALSE) } \arguments{ \item{new}{A vector of new cells} \item{orig}{A vector of existing cells} \item{ordered}{Sort the result to the same order as \code{orig}} } \value{ A numeric vector with new cells in order of the original cells; if no match can be found, returns \code{NULL} } \description{ Match Cells } \concept{utils} \keyword{internal} SeuratObject/man/dimnames.StdAssay.Rd0000644000176200001440000000232314520004144017227 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay5.R \name{dimnames.StdAssay} \alias{dimnames.StdAssay} \alias{dimnames<-.StdAssay} \title{Assay-Level Feature and Cell Names} \usage{ \method{dimnames}{StdAssay}(x) \method{dimnames}{StdAssay}(x) <- value } \arguments{ \item{x}{An \code{\link{Assay5}} object} \item{value}{A two-length list with updated feature and/or cells names} } \value{ \code{dimnames}: A two-length list with the following values: \itemize{ \item A character vector with all features in \code{x} \item A character vector with all cells in \code{x} } \code{dimnames<-}: \code{x} with the feature and/or cell names updated to \code{value} } \description{ Get and set feature and cell names in v5 Assays } \seealso{ \code{\link{Cells}} \code{\link{Features}} v5 Standard Assay object, validity, and interaction methods \code{\link{$.StdAssay}()}, \code{\link{.DollarNames.StdAssay}()}, \code{\link{StdAssay-class}}, \code{\link{StdAssay-validity}}, \code{\link{[.StdAssay}()}, \code{\link{[[.StdAssay}()}, \code{\link{dim.StdAssay}()}, \code{\link{show,StdAssay-method}}, \code{\link{split.StdAssay}()}, \code{\link{subset.StdAssay}()} } \concept{stdassay} \keyword{internal} SeuratObject/man/droplevels.LogMap.Rd0000644000176200001440000000150014520004144017231 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/logmap.R \name{droplevels.LogMap} \alias{droplevels.LogMap} \title{Drop Unused Logical Map Values} \usage{ \method{droplevels}{LogMap}(x, ...) } \arguments{ \item{x}{A \code{LogMap} object} \item{...}{Ignored} } \value{ \code{x} with values not present in any observation removed } \description{ Remove any unused values from a \link[=LogMap]{logical map} } \examples{ map <- LogMap(letters[1:10]) map[['obs']] <- c(1, 3, 7) map[['entry']] <- c(2, 7, 10) # Remove unused values map <- droplevels(map) map map[[]] } \seealso{ Logical map objects, validity, and interaction methods: \code{\link{LogMap-validity}}, \code{\link{LogMap}}, \code{\link{as.matrix.LogMap}()}, \code{\link{intersect.LogMap}()}, \code{\link{labels.LogMap}()} } \concept{logmap} SeuratObject/man/NNIndex.Rd0000644000176200001440000000126414520004144015206 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/neighbor.R \name{Index} \alias{Index} \alias{Index<-} \alias{Index.Neighbor} \alias{Index<-.Neighbor} \title{Get Neighbor algorithm index} \usage{ Index(object, ...) Index(object, ...) <- value \method{Index}{Neighbor}(object, ...) \method{Index}{Neighbor}(object, ...) <- value } \arguments{ \item{object}{An object} \item{...}{Arguments passed to other methods} \item{value}{The index to store} } \value{ Returns the value in the alg.idx slot of the Neighbor object \code{Idents<-}: A Neighbor object with the index stored } \description{ Get Neighbor algorithm index } \concept{data-access} SeuratObject/man/ObjectAccess.Rd0000644000176200001440000000165214520004144016234 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/seurat.R \name{Assays} \alias{Assays} \alias{Graphs} \alias{Neighbors} \alias{Reductions} \alias{Assays.Seurat} \title{Query Specific Object Types} \usage{ Assays(object, ...) Graphs(object, slot = NULL) Neighbors(object, slot = NULL) Reductions(object, slot = NULL) \method{Assays}{Seurat}(object, slot = deprecated(), ...) } \arguments{ \item{object}{A \code{\link{Seurat}} object} \item{...}{Ignored} \item{slot}{Name of component object to return} } \value{ If \code{slot} is \code{NULL}, the names of all component objects in this \code{Seurat} object. Otherwise, the specific object specified } \description{ List the names of \code{\link{Assay}}, \code{\link{DimReduc}}, \code{\link{Graph}}, \code{\link{Neighbor}} objects } \examples{ Assays(pbmc_small) Graphs(pbmc_small) Reductions(object = pbmc_small) } \concept{data-access} SeuratObject/man/CreateDimReducObject.Rd0000644000176200001440000000336014520004144017651 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/dimreduc.R \name{CreateDimReducObject} \alias{CreateDimReducObject} \alias{SetDimReduction} \title{Create a DimReduc object} \usage{ CreateDimReducObject( embeddings = new(Class = "matrix"), loadings = new(Class = "matrix"), projected = new(Class = "matrix"), assay = NULL, stdev = numeric(), key = NULL, global = FALSE, jackstraw = NULL, misc = list() ) } \arguments{ \item{embeddings}{A matrix with the cell embeddings} \item{loadings}{A matrix with the feature loadings} \item{projected}{A matrix with the projected feature loadings} \item{assay}{Assay used to calculate this dimensional reduction} \item{stdev}{Standard deviation (if applicable) for the dimensional reduction} \item{key}{A character string to facilitate looking up features from a specific DimReduc} \item{global}{Specify this as a global reduction (useful for visualizations)} \item{jackstraw}{Results from the JackStraw function} \item{misc}{list for the user to store any additional information associated with the dimensional reduction} } \value{ A \code{\link{DimReduc}} object } \description{ Create a DimReduc object } \examples{ data <- GetAssayData(pbmc_small[["RNA"]], slot = "scale.data") pcs <- prcomp(x = data) pca.dr <- CreateDimReducObject( embeddings = pcs$rotation, loadings = pcs$x, stdev = pcs$sdev, key = "PC", assay = "RNA" ) } \seealso{ Dimensional reduction object, validity, and interaction methods \code{\link{DimReduc-class}}, \code{\link{DimReduc-validity}}, \code{\link{[.DimReduc}()}, \code{\link{[[.DimReduc}()}, \code{\link{dim.DimReduc}()}, \code{\link{merge.DimReduc}()}, \code{\link{print.DimReduc}()}, \code{\link{subset.DimReduc}()} } \concept{dimreduc} SeuratObject/man/DefaultDimReduc.Rd0000644000176200001440000000147014473173564016727 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{DefaultDimReduc} \alias{DefaultDimReduc} \title{Find the default \code{\link{DimReduc}}} \usage{ DefaultDimReduc(object, assay = NULL) } \arguments{ \item{object}{A \code{\link{Seurat}} object} \item{assay}{Name of assay to use; defaults to the default assay of the object} } \value{ The default \code{\link{DimReduc}}, if possible } \description{ Searches for \code{\link{DimReduc}s} matching \dQuote{umap}, \dQuote{tsne}, or \dQuote{pca}, case-insensitive, and in that order. Priority given to \code{\link{DimReduc}s} matching the \code{DefaultAssay} or assay specified (eg. \dQuote{pca} for the default assay weights higher than \dQuote{umap} for a non-default assay) } \examples{ DefaultDimReduc(pbmc_small) } \concept{utils} SeuratObject/man/CastAssay-StdAssay.Rd0000644000176200001440000000136314520004144017327 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay5.R \name{CastAssay-StdAssay} \alias{CastAssay-StdAssay} \alias{CastAssay.StdAssay} \title{Cast Assay Layers} \usage{ \method{CastAssay}{StdAssay}(object, to, layers = NA, verbose = TRUE, ...) } \arguments{ \item{object}{An object} \item{to}{Either a class name or a function that takes a layer and returns the same layer as a new class} \item{layers}{A vector of layers to cast; defaults to all layers} \item{verbose}{Show progress updates} \item{...}{If \code{to} is a function, arguments passed to \code{to}} } \value{ \code{object} with the layers cast to class specified by \code{to} } \description{ Cast layers in v5 assays to other classes } \keyword{internal} SeuratObject/man/aggregate.Rd0000644000176200001440000000427214520004144015633 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/fov.R, R/molecules.R \name{aggregate} \alias{aggregate} \alias{aggregate.FOV} \alias{aggregate.Molecules} \title{Aggregate Molecules into an Expression Matrix} \usage{ \method{aggregate}{FOV}(x, by = NULL, set = NULL, drop = TRUE, ...) \method{aggregate}{Molecules}(x, by, drop = TRUE, ...) } \arguments{ \item{x}{An object with spatially-resolved molecule information} \item{by}{Name of a \code{\link[SeuratObject:Segmentation-class]{Segmentation}} within \code{object} or a \code{\link[SeuratObject:Segmentation-class]{Segmentation}} object} \item{set}{Name of molecule set to aggregate} \item{drop}{Drop molecules not present in a segmentation; if \code{FALSE}, adds a column called \dQuote{\code{boundless}} consisting of molecule counts not in a segmentation} \item{...}{Arguments passed to other methods} } \value{ An expression matrix } \description{ Aggregate Molecules into an Expression Matrix } \section{Progress Updates with \pkg{progressr}}{ This function uses \href{https://cran.r-project.org/package=progressr}{\pkg{progressr}} to render status updates and progress bars. To enable progress updates, wrap the function call in \code{\link[progressr]{with_progress}} or run \code{\link[progressr:handlers]{handlers(global = TRUE)}} before running this function. For more details about \pkg{progressr}, please read \href{https://progressr.futureverse.org/articles/progressr-intro.html}{\code{vignette("progressr-intro")}} } \section{Parallelization with \pkg{future}}{ This function uses \href{https://cran.r-project.org/package=future}{\pkg{future}} to enable parallelization. Parallelization strategies can be set using \code{\link[future]{plan}}. Common plans include \dQuote{\code{sequential}} for non-parallelized processing or \dQuote{\code{multisession}} for parallel evaluation using multiple \R sessions; for other plans, see the \dQuote{Implemented evaluation strategies} section of \code{\link[future:plan]{?future::plan}}. For a more thorough introduction to \pkg{future}, see \href{https://future.futureverse.org/articles/future-1-overview.html}{\code{vignette("future-1-overview")}} } \concept{future} \keyword{internal} SeuratObject/man/as.sparse.Rd0000644000176200001440000000143214473173564015623 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/utils.R \name{as.sparse} \alias{as.sparse} \alias{as.sparse.data.frame} \alias{as.sparse.Matrix} \alias{as.sparse.matrix} \alias{as.sparse.ngCMatrix} \title{Cast to Sparse} \usage{ as.sparse(x, ...) \method{as.sparse}{data.frame}(x, row.names = NULL, ...) \method{as.sparse}{Matrix}(x, ...) \method{as.sparse}{matrix}(x, ...) \method{as.sparse}{ngCMatrix}(x, ...) } \arguments{ \item{x}{An object} \item{...}{Arguments passed to other methods} \item{row.names}{\code{NULL} or a character vector giving the row names for the data; missing values are not allowed} } \value{ A sparse representation of the input data } \description{ Convert dense objects to sparse representations } \concept{utils} SeuratObject/man/Indices.Rd0000644000176200001440000000077214520004144015264 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/neighbor.R \name{Indices} \alias{Indices} \alias{Indices.Neighbor} \title{Get Neighbor nearest neighbor index matrices} \usage{ Indices(object, ...) \method{Indices}{Neighbor}(object, ...) } \arguments{ \item{object}{An object} \item{...}{Arguments passed to other methods} } \value{ A matrix with the nearest neighbor indices } \description{ Get Neighbor nearest neighbor index matrices } \concept{data-access} SeuratObject/man/merge.Assay5.Rd0000644000176200001440000000245014520004144016144 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay5.R \name{merge.Assay5} \alias{merge.Assay5} \title{Merge Assays} \usage{ \method{merge}{Assay5}(x, y, labels = NULL, add.cell.ids = NULL, collapse = FALSE, ...) } \arguments{ \item{x}{An \code{\link{Assay5}} object} \item{y}{One or more \code{\link{Assay5}} objects} \item{labels}{A character vector equal to the number of objects; defaults to \code{as.character(seq_along(c(x, y)))}} \item{add.cell.ids}{A character vector equal to the number of objects provided to append to all cell names; if \code{TRUE}, uses \code{labels} as \code{add.cell.ids}} \item{collapse}{If \code{TRUE}, merge layers of the same name together; if \code{FALSE}, appends \code{labels} to the layer name} \item{...}{Ignored} } \value{ A new v5 assay with data merged from \code{c(x, y)} } \description{ Merge one or more v5 assays together } \details{ \strong{Note}: collapsing layers is currently not supported } \seealso{ v5 Assay object, validity, and interaction methods: \code{\link{$.Assay5}()}, \code{\link{Assay5-class}}, \code{\link{Assay5-validity}}, \code{\link{[.Assay5}()}, \code{\link{[[.Assay5}()}, \code{\link{dim.Assay5}()}, \code{\link{dimnames.Assay5}()}, \code{\link{split.Assay5}()}, \code{\link{subset.Assay5}()} } \concept{assay5} SeuratObject/man/Command.Rd0000644000176200001440000000130014473173564015274 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/seurat.R \name{Command} \alias{Command} \alias{Command.Seurat} \title{Get SeuratCommands} \usage{ Command(object, ...) \method{Command}{Seurat}(object, command = NULL, value = NULL, ...) } \arguments{ \item{object}{An object} \item{...}{Arguments passed to other methods} \item{command}{Name of the command to pull, pass \code{NULL} to get the names of all commands run} \item{value}{Name of the parameter to pull the value for} } \value{ Either a SeuratCommand object or the requested parameter value } \description{ Pull information on previously run commands in the Seurat object. } \concept{data-access} SeuratObject/man/dot-DefaultFOV.Rd0000644000176200001440000000061414520004144016424 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{.DefaultFOV} \alias{.DefaultFOV} \title{Find the Default FOV} \usage{ .DefaultFOV(object, assay = NULL) } \arguments{ \item{object}{A \code{{Seurat}} object} } \value{ ... } \description{ Attempts to find the \dQuote{default} FOV using the revamped spatial framework } \concept{utils} \keyword{internal} SeuratObject/man/Distances.Rd0000644000176200001440000000077114473173564015646 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/neighbor.R \name{Distances} \alias{Distances} \alias{Distances.Neighbor} \title{Get the Neighbor nearest neighbors distance matrix} \usage{ Distances(object, ...) \method{Distances}{Neighbor}(object, ...) } \arguments{ \item{object}{An object} \item{...}{Arguments passed to other methods} } \value{ The distance matrix } \description{ Get the Neighbor nearest neighbors distance matrix } \concept{data-access} SeuratObject/man/sub-sub-.Assay5.Rd0000644000176200001440000000254614520004144016510 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay5.R \name{[[.Assay5} \alias{[[.Assay5} \alias{[[<-,Assay5,ANY,ANY,ANY-method} \alias{head.Assay5} \alias{tail.Assay5} \title{Feature-Level Meta Data} \usage{ \method{[[}{Assay5}(x, i, j, ..., drop = FALSE) \S4method{[[}{Assay5,ANY,ANY,ANY}(x, i, j, ...) <- value \method{head}{Assay5}(x, n = 10L, ...) \method{tail}{Assay5}(x, n = 10L, ...) } \arguments{ \item{x}{An \code{\link{Assay5}} object} \item{i}{Name of feature-level meta data to fetch or add} \item{j}{Ignored} \item{...}{Ignored} \item{drop}{See \code{\link{drop}}} \item{value}{Feature-level meta data to add} \item{n}{Number of meta data rows to show} } \value{ \code{[[}: The feature-level meta data for \code{i} \code{[[<-}: \code{x} with \code{value} added as \code{i} in feature-level meta data \code{head}: The first \code{n} rows of feature-level meta data \code{tail}: the last \code{n} rows of feature-level meta data } \description{ Get and set feature-level meta data } \seealso{ v5 Assay object, validity, and interaction methods: \code{\link{$.Assay5}()}, \code{\link{Assay5-class}}, \code{\link{Assay5-validity}}, \code{\link{[.Assay5}()}, \code{\link{dim.Assay5}()}, \code{\link{dimnames.Assay5}()}, \code{\link{merge.Assay5}()}, \code{\link{split.Assay5}()}, \code{\link{subset.Assay5}()} } \concept{assay5} SeuratObject/man/dot-Subobjects.Rd0000644000176200001440000000165714520004144016600 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{.Subobjects} \alias{.Subobjects} \title{Get the Subobject Names} \usage{ .Subobjects(object, exclude = c("misc", "tools"), collapse = TRUE, ...) } \arguments{ \item{object}{An \link[methods:Classes_Details]{S4} object} \item{exclude}{A character vector of slot names to exclude} \item{collapse}{Collapse the list into a vector} \item{...}{Arguments passed to \code{\link{IsNamedList}}} } \value{ If \code{collapse = TRUE}, then a vector with the names of all subobjects; otherwise, a named list where the names are the names of the collections and the values are the names of subobjects within the collection } \description{ Get the Subobject Names } \examples{ .Subobjects(pbmc_small) } \seealso{ \code{\link{.Collections}()}, \code{\link{.FilterObjects}()}, \code{\link{.FindObject}()} } \concept{subobjects} \keyword{internal} \keyword{utils} SeuratObject/man/dot-FilterObjects.Rd0000644000176200001440000000134314520004144017224 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{.FilterObjects} \alias{.FilterObjects} \title{Find Subobjects Of A Certain Class} \usage{ .FilterObjects(object, classes.keep = c("Assay", "StdAssay", "DimReduc")) } \arguments{ \item{object}{An \link[methods:Classes_Details]{S4} object} \item{classes.keep}{A vector of classes to keep} } \value{ A vector of object names that are of class \code{classes.keep} } \description{ Find Subobjects Of A Certain Class } \examples{ .FilterObjects(pbmc_small) .FilterObjects(pbmc_small, "Graph") } \seealso{ \code{\link{.Collections}()}, \code{\link{.FindObject}()}, \code{\link{.Subobjects}()} } \concept{subobjects} \concept{utils} \keyword{internal} SeuratObject/man/RandomName.Rd0000644000176200001440000000130314520004144015716 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{RandomName} \alias{RandomName} \title{Generate a random name} \usage{ RandomName(length = 5L, chars = letters, ...) } \arguments{ \item{length}{How long should the name be} \item{chars}{A vector of 1-length characters to use to generate the name} \item{...}{Extra parameters passed to \code{\link[base]{sample}}} } \value{ A character with \code{nchar == length} of randomly sampled letters } \description{ Make a name from randomly sampled characters, pasted together with no spaces } \examples{ set.seed(42L) RandomName() RandomName(7L, replace = TRUE) } \seealso{ \code{\link[base]{sample}} } \concept{utils} SeuratObject/man/Embeddings.Rd0000644000176200001440000000153314505663124015757 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/dimreduc.R, R/seurat.R \name{Embeddings} \alias{Embeddings} \alias{Embeddings.DimReduc} \alias{Embeddings.Seurat} \title{Get Cell Embeddings} \usage{ Embeddings(object, ...) \method{Embeddings}{DimReduc}(object, ...) \method{Embeddings}{Seurat}(object, reduction = "pca", ...) } \arguments{ \item{object}{An object} \item{...}{Arguments passed to other methods} \item{reduction}{Name of reduction to pull cell embeddings for} } \value{ The embeddings matrix } \description{ Get Cell Embeddings } \examples{ # Get the embeddings directly from a DimReduc object Embeddings(object = pbmc_small[["pca"]])[1:5, 1:5] # Get the embeddings from a specific DimReduc in a Seurat object Embeddings(object = pbmc_small, reduction = "pca")[1:5, 1:5] } \concept{data-access} SeuratObject/man/cash-.Assay.Rd0000644000176200001440000000203614520004144015753 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay.R \name{$.Assay} \alias{$.Assay} \alias{$<-.Assay} \title{Layer Data} \usage{ \method{$}{Assay}(x, i) \method{$}{Assay}(x, i) <- value } \arguments{ \item{x}{An \code{\link{Assay}} object} \item{i}{Name of layer data to get or set} \item{value}{A matrix-like object to add as a new layer} } \value{ {$}: Layer data for layer \code{i} \code{$<-}: \code{x} with layer data \code{value} saved as \code{i} } \description{ Get and set layer data } \examples{ rna <- pbmc_small[["RNA"]] # Fetch a layer with `$` rna$data[1:10, 1:4] # Add a layer with `$` rna$data <- rna$counts rna$data[1:10, 1:4] } \seealso{ v3 Assay object, validity, and interaction methods: \code{\link{Assay-class}}, \code{\link{Assay-validity}}, \code{\link{CreateAssayObject}()}, \code{\link{[.Assay}()}, \code{\link{[[.Assay}()}, \code{\link{dim.Assay}()}, \code{\link{dimnames.Assay}()}, \code{\link{merge.Assay}()}, \code{\link{split.Assay}()}, \code{\link{subset.Assay}()} } \concept{assay} SeuratObject/man/s4list.Rd0000644000176200001440000000352314520004144015125 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/utils.R \name{s4list} \alias{s4list} \alias{S4ToList} \alias{IsS4List} \alias{ListToS4} \alias{S4ToList.default} \alias{S4ToList.list} \title{S4/List Conversion} \usage{ S4ToList(object) IsS4List(x) ListToS4(x) \method{S4ToList}{default}(object) \method{S4ToList}{list}(object) } \arguments{ \item{object}{An S4 object} \item{x}{A list with an S4 class definition (\dQuote{\code{classDef}}) attribute} } \value{ \code{S4ToList}: A list with an S4 class definition attribute \code{IsS4List}: \code{TRUE} if \code{x} is a list with an S4 class definition attribute \code{ListToS4}: An S4 object as defined by the S4 class definition attribute } \description{ Convert S4 objects to lists and vice versa. Useful for declassing an S4 object while keeping track of it's class using attributes (see section \strong{S4 Class Definition Attributes} below for more details). Both \code{ListToS4} and \code{S4ToList} are recursive functions, affecting all lists/S4 objects contained as sub-lists/sub-objects } \section{S4 Class Definition Attributes}{ S4 classes are scoped to the package and class name. In order to properly track which class a list is generated from in order to build a new one, these function use an \code{\link[base:attr]{attribute}} to denote the class name and package of origin. This attribute is stored as 1-length character vector named \dQuote{\code{classDef}} and takes the form of \dQuote{\code{package:class}} } \examples{ # Turn an S4 object into a list pbmc.list <- S4ToList(pbmc_small) class(pbmc.list) attributes(pbmc.list) str(pbmc.list$reductions) IsS4List(pbmc.list) pbmc2 <- ListToS4(pbmc.list) pbmc2 class(pbmc2) Reductions(pbmc2) validObject(pbmc2) } \seealso{ \code{\link{ClassKey}()} } \concept{s4list} \concept{utils} \keyword{internal} SeuratObject/man/GetImage.Rd0000644000176200001440000000241014473173564015403 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/seurat.R \name{GetImage} \alias{GetImage} \alias{GetImage.Seurat} \title{Get image data} \usage{ GetImage(object, mode = c("grob", "raster", "plotly", "raw"), ...) \method{GetImage}{Seurat}( object, mode = c("grob", "raster", "plotly", "raw"), image = NULL, ... ) } \arguments{ \item{object}{An object} \item{mode}{How to return the image; should accept one of \dQuote{grob}, \dQuote{raster}, \dQuote{plotly}, or \dQuote{raw}} \item{...}{Arguments passed to other methods} \item{image}{Name of \code{SpatialImage} object to pull image data for; if \code{NULL}, will attempt to select an image automatically} } \value{ Image data, varying depending on the value of \code{mode}: \describe{ \item{\dQuote{grob}}{ An object representing image data inheriting from \code{grob} objects (eg. \code{rastergrob}) } \item{\dQuote{raster}}{An object of class \code{raster}} \item{\dQuote{plotly}}{ A list with image data suitable for Plotly rendering, see \code{\link[plotly:layout]{plotly::layout}} for more details } \item{\dQuote{raw}}{The raw image data as stored in the object} } } \description{ Get image data } \seealso{ \code{\link[plotly]{layout}} } \concept{data-access} SeuratObject/man/PackageCheck.Rd0000644000176200001440000000134214520004144016171 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{PackageCheck} \alias{PackageCheck} \title{Check the existence of a package} \usage{ PackageCheck(..., error = TRUE) } \arguments{ \item{...}{Package names} \item{error}{If true, throw an error if the package doesn't exist} } \value{ Invisibly returns boolean denoting if the package is installed } \description{ Check the existence of a package } \section{Lifecycle}{ \Sexpr[stage=build,results=rd]{lifecycle::badge("deprecated")} \code{PackageCheck} was deprecated in version 5.0.0; please use \code{\link[rlang:check_installed]{rlang::check_installed}()} instead } \examples{ PackageCheck("SeuratObject", error = FALSE) } \concept{utils} SeuratObject/man/CheckDots.Rd0000644000176200001440000000250414520004144015550 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{CheckDots} \alias{CheckDots} \title{Check the Use of Dots} \usage{ CheckDots(..., fxns = NULL) } \arguments{ \item{...}{Arguments passed to a function that fall under \code{...}} \item{fxns}{A list/vector of functions or function names} } \value{ Emits either an error or warning if an argument passed is unused; invisibly returns \code{NULL} } \description{ Function to check the use of unused arguments passed to \code{...}; this function is designed to be called from another function to see if an argument passed to \code{...} remains unused and alert the user if so. Also accepts a vector of function or function names to see if \code{...} can be used in a downstream function } \details{ Behavior of \code{CheckDots} can be controlled by the following option(s): \describe{ \item{\dQuote{\code{Seurat.checkdots}}}{Control how to alert the presence of unused arguments in \code{...}; choose from \itemize{ \item \dQuote{\code{warn}}: emit a warning (default) \item \dQuote{\code{error}}: throw an error \item \dQuote{\code{silent}}: no not alert the presence of unused arguments in \code{...} } } } } \examples{ \dontrun{ f <- function(x, ...) { CheckDots(...) return(x ^ 2) } f(x = 3, y = 9) } } \concept{utils} \keyword{internal} SeuratObject/man/show-LogMap-method.Rd0000644000176200001440000000070214520004144017312 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/logmap.R \name{show,LogMap-method} \alias{show,LogMap-method} \title{\code{\link{LogMap}} Object Overview} \usage{ \S4method{show}{LogMap}(object) } \arguments{ \item{object}{A \code{\link{LogMap}} object} } \value{ Prints summary to \code{\link[base]{stdout}} and invisibly returns \code{NULL} } \description{ Overview of a \code{\link{LogMap}} object } \concept{logmap} SeuratObject/man/colMeans-Seurat-method.Rd0000644000176200001440000000307214520004144020162 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/seurat.R \name{colMeans,Seurat-method} \alias{colMeans,Seurat-method} \alias{colSums,Seurat-method} \alias{rowMeans,Seurat-method} \alias{rowSums,Seurat-method} \title{Row and Column Sums and Means} \usage{ \S4method{colMeans}{Seurat}(x, na.rm = FALSE, dims = 1, ..., slot = "data") \S4method{colSums}{Seurat}(x, na.rm = FALSE, dims = 1, ..., slot = "data") \S4method{rowMeans}{Seurat}(x, na.rm = FALSE, dims = 1, ..., slot = "data") \S4method{rowSums}{Seurat}(x, na.rm = FALSE, dims = 1, ..., slot = "data") } \arguments{ \item{x}{A \code{\link{Seurat}} object} \item{na.rm}{logical. Should missing values (including \code{NaN}) be omitted from the calculations?} \item{dims}{completely ignored by the \code{Matrix} methods.} \item{...}{potentially further arguments, for method \code{<->} generic compatibility.} \item{slot}{Name of assay expression matrix to calculate column/row means/sums on} } \value{ \code{colMeans}: the column (cell-wise) means of \code{slot} \code{colSums}: the column (cell-wise) sums of \code{slot} \code{rowMeans}: the row (feature-wise) means of \code{slot} \code{rowSums}: the row (feature-wise) sums of \code{slot} } \description{ Calculate \code{\link{rowSums}}, \code{\link{colSums}}, \code{\link{rowMeans}}, and \code{\link{colMeans}} on \code{\link{Seurat}} objects } \examples{ head(colMeans(pbmc_small)) head(colSums(pbmc_small)) head(rowMeans(pbmc_small)) head(rowSums(pbmc_small)) } \seealso{ \code{\link{Seurat}} } \concept{seurat} \keyword{internal} SeuratObject/man/subset.StdAssay.Rd0000644000176200001440000000201514520004144016735 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay5.R \name{subset.StdAssay} \alias{subset.StdAssay} \title{Subset an Assay} \usage{ \method{subset}{StdAssay}(x, cells = NULL, features = NULL, layers = NULL, ...) } \arguments{ \item{x}{An \code{\link{Assay5}} object} \item{cells}{Cell names} \item{features}{Feature names} \item{layers}{Layer to keep; defaults to all layers} \item{...}{Ignored} } \value{ \code{x} with just the cells and features specified by \code{cells} and \code{features} for the layers specified by \code{layers} } \description{ Subset an Assay } \seealso{ v5 Standard Assay object, validity, and interaction methods \code{\link{$.StdAssay}()}, \code{\link{.DollarNames.StdAssay}()}, \code{\link{StdAssay-class}}, \code{\link{StdAssay-validity}}, \code{\link{[.StdAssay}()}, \code{\link{[[.StdAssay}()}, \code{\link{dim.StdAssay}()}, \code{\link{dimnames.StdAssay}()}, \code{\link{show,StdAssay-method}}, \code{\link{split.StdAssay}()} } \concept{stdassay} \keyword{internal} SeuratObject/man/Assay5-class.Rd0000644000176200001440000000423714520004144016156 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay5.R \docType{class} \name{Assay5-class} \alias{Assay5-class} \alias{Assay5} \title{The v5 \code{Assay} Object} \description{ The v5 \code{Assay} is the typical \code{Assay} class used in \pkg{Seurat} v5; ... } \section{Slots}{ \describe{ \item{\code{layers}}{A named list containing expression matrices; each matrix should be a two-dimensional object containing some subset of cells and features defined in the \code{cells} and \code{features} slots. Cell and feature membership is recorded in the \code{cells} and \code{features} slots, respectively} \item{\code{cells}}{A \link[=LogMap]{logical mapping} of cell names and layer membership; this map contains all the possible cells that this assay can contain. New layers must have some subset of cells present in this map} \item{\code{features}}{A \link[=LogMap]{logical mapping} of feature names and layer membership; this map contains all the possible features that this assay can contain. New layers must have some subset of features present in this map} \item{\code{default}}{A one-length integer with the end index of the \link[=DefaultLayer]{default layer}; the default layer be all layers up to and including the layer at index \code{default}} \item{\code{assay.orig}}{Original assay that this assay is based off of; used to track assay provenance} \item{\code{meta.data}}{A \link[base:data.frame]{data frame} with feature-level meta data; should have the same number of rows as \code{features}} \item{\code{misc}}{A named list of unstructured miscellaneous data} \item{\code{key}}{A one-length character vector with the object's key; keys must be one or more alphanumeric characters followed by an underscore \dQuote{\code{_}} (regex pattern \dQuote{\code{\Sexpr[stage=build]{SeuratObject:::.KeyPattern()}}})} }} \seealso{ v5 Assay object, validity, and interaction methods: \code{\link{$.Assay5}()}, \code{\link{Assay5-validity}}, \code{\link{[.Assay5}()}, \code{\link{[[.Assay5}()}, \code{\link{dim.Assay5}()}, \code{\link{dimnames.Assay5}()}, \code{\link{merge.Assay5}()}, \code{\link{split.Assay5}()}, \code{\link{subset.Assay5}()} } \concept{assay5} SeuratObject/man/set-if-na.Rd0000644000176200001440000000136714520004144015472 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{set-if-na} \alias{set-if-na} \alias{\%NA\%} \alias{\%na\%} \alias{\%!NA\%} \alias{\%!na\%} \title{Set If or If Not \code{NA}} \usage{ x \%NA\% y x \%na\% y x \%!NA\% y x \%!na\% y } \arguments{ \item{x}{An object to test} \item{y}{A default value} } \value{ For \code{\%NA\%}: \code{y} if \code{x} is \code{\link[base]{NA}}; otherwise \code{x} For \code{\%!NA\%}: \code{y} if \code{x} is \strong{not} \code{\link[base]{NA}}; otherwise \code{x} } \description{ Set a default value depending on if an object is \code{\link[base]{NA}} } \examples{ # Set if NA 1 \%NA\% 2 NA \%NA\% 2 # Set if *not* NA 1 \%!NA\% 2 NA \%!NA\% 2 } \concept{utils} \keyword{internal} SeuratObject/man/CreateFOV.Rd0000644000176200001440000000355214520004201015455 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/fov.R \name{CreateFOV} \alias{CreateFOV} \alias{CreateFOV.Centroids} \alias{CreateFOV.data.frame} \alias{CreateFOV.list} \alias{CreateFOV.Segmentation} \title{Create Spatial Coordinates} \usage{ CreateFOV(coords, ...) \method{CreateFOV}{Centroids}( coords, molecules = NULL, assay = "Spatial", key = NULL, name = NULL, ... ) \method{CreateFOV}{data.frame}( coords, type = c("segmentation", "centroids"), nsides = Inf, radius = NULL, theta = 0L, molecules = NULL, assay = "Spatial", key = NULL, name = NULL, ... ) \method{CreateFOV}{list}(coords, molecules = NULL, assay = "Spatial", key = NULL, ...) \method{CreateFOV}{Segmentation}( coords, molecules = NULL, assay = "Spatial", key = NULL, name = NULL, ... ) } \arguments{ \item{coords}{Spatial coordinates} \item{...}{Arguments passed to other methods} \item{molecules}{A \code{\link[base]{data.frame}} with spatially-resolved molecule information or a \code{\link[SeuratObject:Molecules-class]{Molecules}} object} \item{assay}{Name of associated assay} \item{key}{Key for these spatial coordinates} \item{name}{When \code{coords} is a \code{\link[base]{data.frame}}, \code{\link[SeuratObject:Centroids-class]{Centroids}}, or \code{\link[SeuratObject:Segmentation-class]{Segmentation}}, name to store coordinates as} \item{type}{When providing a \code{\link[base]{data.frame}}, specify if the coordinates represent a cell segmentation or voxel centroids} \item{nsides}{The number of sides to represent cells/spots; pass \code{\link[base]{Inf}} to plot as circles} \item{radius}{Radius of shapes when plotting} \item{theta}{Angle to adjust shapes when plotting} } \value{ A \code{\link{FOV}} object } \description{ Create Spatial Coordinates } \seealso{ \code{\link{FOV-class}} } \concept{spatial} SeuratObject/man/dot-ClassPkg.Rd0000644000176200001440000000125714520004144016200 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/utils.R \name{.ClassPkg} \alias{.ClassPkg} \alias{.ClassPkg.default} \alias{.ClassPkg.DelayedArray} \alias{.ClassPkg.R6} \alias{.ClassPkg.R6ClassGenerator} \title{Get the Package that Defines a Class} \usage{ .ClassPkg(object) \method{.ClassPkg}{default}(object) \method{.ClassPkg}{DelayedArray}(object) \method{.ClassPkg}{R6}(object) \method{.ClassPkg}{R6ClassGenerator}(object) } \arguments{ \item{object}{An object} } \value{ The package that defines the class of \code{object} } \description{ Get the Package that Defines a Class } \examples{ .ClassPkg(pbmc_small) } \keyword{internal} SeuratObject/man/merge.Assay.Rd0000644000176200001440000000237314520004144016063 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay.R \name{merge.Assay} \alias{merge.Assay} \title{Merge Assays} \usage{ \method{merge}{Assay}( x = NULL, y = NULL, add.cell.ids = NULL, merge.data = TRUE, labels = NULL, collapse = TRUE, ... ) } \arguments{ \item{x}{An \code{\link{Assay}} object} \item{y}{One or more \code{\link{Assay}} objects} \item{add.cell.ids}{A character vector of \code{length(x = c(x, y))}; appends the corresponding values to the start of each objects' cell names} \item{merge.data}{Merge the data slots instead of just merging the counts (which requires renormalization); this is recommended if the same normalization approach was applied to all objects} \item{labels, collapse}{Currently unused} \item{...}{Ignored} } \value{ A new assay with data merged from \code{c(x, y)} } \description{ Merge one or more v3 assays together } \seealso{ v3 Assay object, validity, and interaction methods: \code{\link{$.Assay}()}, \code{\link{Assay-class}}, \code{\link{Assay-validity}}, \code{\link{CreateAssayObject}()}, \code{\link{[.Assay}()}, \code{\link{[[.Assay}()}, \code{\link{dim.Assay}()}, \code{\link{dimnames.Assay}()}, \code{\link{split.Assay}()}, \code{\link{subset.Assay}()} } \concept{assay} SeuratObject/man/sub-.StdAssay.Rd0000644000176200001440000000221014520004144016273 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay5.R \name{[.StdAssay} \alias{[.StdAssay} \alias{[<-,StdAssay,character,ANY,ANY-method} \title{Layer Data} \usage{ \method{[}{StdAssay}(x, i = missing_arg(), j = missing_arg(), ...) \S4method{[}{StdAssay,character,ANY,ANY}(x, i, j, ...) <- value } \arguments{ \item{x}{An \code{\link{Assay5}} object} \item{i}{Name of layer data to get or set} \item{j}{Ignored} \item{...}{Arguments passed to \code{\link{LayerData}}} \item{value}{A matrix-like object to add as a new layer} } \value{ \code{[}: The layer data for layer \code{i} \code{[<-}: \code{x} with layer data \code{value} saved as \code{i} } \description{ Get and set layer data } \seealso{ v5 Standard Assay object, validity, and interaction methods \code{\link{$.StdAssay}()}, \code{\link{.DollarNames.StdAssay}()}, \code{\link{StdAssay-class}}, \code{\link{StdAssay-validity}}, \code{\link{[[.StdAssay}()}, \code{\link{dim.StdAssay}()}, \code{\link{dimnames.StdAssay}()}, \code{\link{show,StdAssay-method}}, \code{\link{split.StdAssay}()}, \code{\link{subset.StdAssay}()} } \concept{stdassay} \keyword{internal} SeuratObject/man/CellsByImage.Rd0000644000176200001440000000123214473173564016222 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/seurat.R \name{CellsByImage} \alias{CellsByImage} \title{Get a vector of cell names associated with an image (or set of images)} \usage{ CellsByImage(object, images = NULL, unlist = FALSE) } \arguments{ \item{object}{Seurat object} \item{images}{Vector of image names} \item{unlist}{Return as a single vector of cell names as opposed to a list, named by image name.} } \value{ A vector of cell names } \description{ Get a vector of cell names associated with an image (or set of images) } \examples{ \dontrun{ CellsByImage(object = object, images = "slice1") } } \concept{data-access} SeuratObject/man/dot-DollarNames.SeuratCommand.Rd0000644000176200001440000000143014520004144021424 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/command.R \name{.DollarNames.SeuratCommand} \alias{.DollarNames.SeuratCommand} \title{Dollar-sign Autocompletion} \usage{ \method{.DollarNames}{SeuratCommand}(x, pattern = "") } \arguments{ \item{x}{A \code{\link{SeuratCommand}} object} \item{pattern}{ A regular expression. Only matching names are returned. } } \value{ The parameter name matches for \code{pattern} } \description{ Autocompletion for \code{$} access on a \code{\link{SeuratCommand}} object } \seealso{ Command log object and interaction methods \code{\link{$.SeuratCommand}()}, \code{\link{LogSeuratCommand}()}, \code{\link{SeuratCommand-class}}, \code{\link{[.SeuratCommand}()}, \code{\link{as.list.SeuratCommand}()} } \concept{command} SeuratObject/man/dot-DiskLoad.Rd0000644000176200001440000000206014520004144016154 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/utils.R \name{.DiskLoad} \alias{.DiskLoad} \alias{.DiskLoad.default} \alias{.DiskLoad.10xMatrixH5} \alias{.DiskLoad.AnnDataMatrixH5} \alias{.DiskLoad.DelayedMatrix} \alias{.DiskLoad.H5ADMatrix} \alias{.DiskLoad.HDF5Matrix} \alias{.DiskLoad.IterableMatrix} \alias{.DiskLoad.MatrixDir} \alias{.DiskLoad.MatrixH5} \alias{.DiskLoad.TileDBMatrix} \title{Disk Loading Function} \usage{ .DiskLoad(x) \method{.DiskLoad}{default}(x) \method{.DiskLoad}{`10xMatrixH5`}(x) \method{.DiskLoad}{AnnDataMatrixH5}(x) \method{.DiskLoad}{DelayedMatrix}(x) \method{.DiskLoad}{H5ADMatrix}(x) \method{.DiskLoad}{HDF5Matrix}(x) \method{.DiskLoad}{IterableMatrix}(x) \method{.DiskLoad}{MatrixDir}(x) \method{.DiskLoad}{MatrixH5}(x) \method{.DiskLoad}{TileDBMatrix}(x) } \arguments{ \item{x}{A file-backed object} } \value{ A one-length character that defines a function to load a matrix from a file } \description{ Generate a function to load a matrix from an on-disk file } \keyword{internal} SeuratObject/man/subset.DimReduc.Rd0000644000176200001440000000154514520004144016705 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/dimreduc.R \name{subset.DimReduc} \alias{subset.DimReduc} \title{Subset a Dimensional Reduction} \usage{ \method{subset}{DimReduc}(x, cells = NULL, features = NULL, ...) } \arguments{ \item{x}{A \code{\link{DimReduc}} object} \item{cells, features}{Cells and features to keep during the subset} \item{...}{Ignored} } \value{ \code{x} for cells \code{cells} and features \code{features} } \description{ Subset a \code{\link{DimReduc}} object } \seealso{ Dimensional reduction object, validity, and interaction methods \code{\link{CreateDimReducObject}()}, \code{\link{DimReduc-class}}, \code{\link{DimReduc-validity}}, \code{\link{[.DimReduc}()}, \code{\link{[[.DimReduc}()}, \code{\link{dim.DimReduc}()}, \code{\link{merge.DimReduc}()}, \code{\link{print.DimReduc}()} } \concept{dimreduc} SeuratObject/man/UpdateSlots.Rd0000644000176200001440000000054114473173564016173 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{UpdateSlots} \alias{UpdateSlots} \title{Update slots in an object} \usage{ UpdateSlots(object) } \arguments{ \item{object}{An object to update} } \value{ \code{object} with the latest slot definitions } \description{ Update slots in an object } \concept{utils} SeuratObject/man/show-Assay-method.Rd0000644000176200001440000000071714520004144017221 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay.R \name{show,Assay-method} \alias{show,Assay-method} \title{V3 Assay Overview} \usage{ \S4method{show}{Assay}(object) } \value{ Prints summary to \code{\link[base]{stdout}} and invisibly returns \code{NULL} } \description{ Overview of an \code{\link{Assay}} object } \examples{ rna <- pbmc_small[["RNA"]] rna } \seealso{ \code{\link{Assay}} } \concept{assay} \keyword{internal} SeuratObject/man/IsMatrixEmpty.Rd0000644000176200001440000000104614520004144016460 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/utils.R \name{IsMatrixEmpty} \alias{IsMatrixEmpty} \alias{IsMatrixEmpty.default} \title{Check if a matrix is empty} \usage{ IsMatrixEmpty(x) \method{IsMatrixEmpty}{default}(x) } \arguments{ \item{x}{A matrix} } \value{ Whether or not \code{x} is empty } \description{ Takes a matrix and asks if it's empty (either 0x0 or 1x1 with a value of NA) } \examples{ IsMatrixEmpty(new("matrix")) IsMatrixEmpty(matrix()) IsMatrixEmpty(matrix(1:3)) } \concept{utils} SeuratObject/man/dot-FilePath.Rd0000644000176200001440000000112114520004144016153 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/utils.R \name{.FilePath} \alias{.FilePath} \alias{.FilePath.default} \alias{.FilePath.DelayedMatrix} \alias{.FilePath.IterableMatrix} \title{Find a File Path} \usage{ .FilePath(x) \method{.FilePath}{default}(x) \method{.FilePath}{DelayedMatrix}(x) \method{.FilePath}{IterableMatrix}(x) } \arguments{ \item{x}{A file-backed object} } \value{ The path to the file that backs \code{x}; if \code{x} is not a file-backed object, returns \code{NULL} } \description{ Find a File Path } \keyword{internal} SeuratObject/man/cash-.SeuratCommand.Rd0000644000176200001440000000137314520004144017440 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/command.R \name{$.SeuratCommand} \alias{$.SeuratCommand} \title{Command Log Parameter Access} \usage{ \method{$}{SeuratCommand}(x, i) } \arguments{ \item{x}{A \code{\link{SeuratCommand}} object} \item{i}{A parameter name} } \value{ The value for parameter \code{i} } \description{ Pull parameter values from a \code{\link{SeuratCommand}} object } \examples{ cmd <- pbmc_small[["NormalizeData.RNA"]] cmd$normalization.method } \seealso{ Command log object and interaction methods \code{\link{.DollarNames.SeuratCommand}()}, \code{\link{LogSeuratCommand}()}, \code{\link{SeuratCommand-class}}, \code{\link{[.SeuratCommand}()}, \code{\link{as.list.SeuratCommand}()} } \concept{command} SeuratObject/man/SpatialImage-methods.Rd0000644000176200001440000001503614473173564017732 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/spatial.R \name{SpatialImage-methods} \alias{SpatialImage-methods} \alias{Cells.SpatialImage} \alias{DefaultAssay.SpatialImage} \alias{DefaultAssay<-.SpatialImage} \alias{GetImage.SpatialImage} \alias{GetTissueCoordinates.SpatialImage} \alias{IsGlobal.SpatialImage} \alias{Key.SpatialImage} \alias{Key<-.SpatialImage} \alias{Radius.SpatialImage} \alias{RenameCells.SpatialImage} \alias{[.SpatialImage} \alias{dim.SpatialImage} \alias{subset.SpatialImage} \alias{show,SpatialImage-method} \title{\code{SpatialImage} methods} \usage{ \method{Cells}{SpatialImage}(x, ...) \method{DefaultAssay}{SpatialImage}(object, ...) \method{DefaultAssay}{SpatialImage}(object, ...) <- value \method{GetImage}{SpatialImage}(object, mode = c("grob", "raster", "plotly", "raw"), ...) \method{GetTissueCoordinates}{SpatialImage}(object, ...) \method{IsGlobal}{SpatialImage}(object, ...) \method{Key}{SpatialImage}(object, ...) \method{Key}{SpatialImage}(object, ...) <- value \method{Radius}{SpatialImage}(object) \method{RenameCells}{SpatialImage}(object, new.names = NULL, ...) \method{[}{SpatialImage}(x, i, ...) \method{dim}{SpatialImage}(x) \method{subset}{SpatialImage}(x, cells, ...) \S4method{show}{SpatialImage}(object) } \arguments{ \item{x, object}{A \code{SpatialImage}-derived object} \item{...}{Arguments passed to other methods} \item{value}{Depends on the method: \describe{ \item{\code{DefaultAssay<-}}{Assay that the image should be associated with} \item{\code{Key<-}}{New key for the image} }} \item{mode}{How to return the image; should accept one of \dQuote{grob}, \dQuote{raster}, \dQuote{plotly}, or \dQuote{raw}} \item{new.names}{vector of new cell names} \item{i, cells}{A vector of cells to keep} } \value{ \strong{[Override]} \code{Cells}: should return cell names \code{DefaultAssay}: The associated assay of a \code{SpatialImage}-derived object \code{DefaultAssay<-}: \code{object} with the associated assay updated \strong{[Override]} \code{GetImage}: The image data from a \code{SpatialImage}-derived object \strong{[Override]} \code{GetTissueCoordinates}: ... \code{IsGlobal}: returns \code{TRUE} as images are, by default, global \code{Key}: The key for a \code{SpatialImage}-derived object \code{Key<-}: \code{object} with the key set to \code{value} \code{Radius}: The spot radius size; by default, returns \code{NULL} \strong{[Override]} \code{RenameCells}: \code{object} with the new cell names \code{[}, \code{subset}: \code{x}/\code{object} for only the cells requested \strong{[Override]} \code{dim}: The dimensions of the image data in (Y, X) format \code{show}: Prints summary to \code{\link[base]{stdout}} and invisibly returns \code{NULL} } \description{ Methods defined on the \code{\link{SpatialImage}} class. Some of these methods must be overridden in order to ensure proper functionality of the derived classes (see \strong{Required methods} below). Other methods are designed to work across all \code{SpatialImage}-derived subclasses, and should only be overridden if necessary } \section{Functions}{ \itemize{ \item \code{Cells(SpatialImage)}: Get the cell names from an image (\strong{[Override]}) \item \code{DefaultAssay(SpatialImage)}: Get the associated assay of a \code{SpatialImage}-derived object \item \code{DefaultAssay(SpatialImage) <- value}: Set the associated assay of a \code{SpatialImage}-derived object \item \code{GetImage(SpatialImage)}: Get the image data from a \code{SpatialImage}-derived object \item \code{GetTissueCoordinates(SpatialImage)}: Get tissue coordinates for a \code{SpatialImage}-derived object (\strong{[Override]}) \item \code{IsGlobal(SpatialImage)}: Globality test for \code{SpatialImage}-derived object \item \code{Key(SpatialImage)}: Get the key for a \code{SpatialImage}-derived object \item \code{Key(SpatialImage) <- value}: Set the key for a \code{SpatialImage}-derived object \item \code{Radius(SpatialImage)}: Get the spot radius size \item \code{RenameCells(SpatialImage)}: Rename cells in a \code{SpatialImage}-derived object (\strong{[Override]}) \item \code{[}: Subset a \code{SpatialImage}-derived object \item \code{dim(SpatialImage)}: Get the plotting dimensions of an image (\strong{[Override]}) \item \code{subset(SpatialImage)}: Subset a \code{SpatialImage}-derived object (\strong{[Override]}) \item \code{show(SpatialImage)}: Overview of a \code{SpatialImage}-derived object }} \section{Provided methods}{ These methods are defined on the \code{SpatialImage} object and should not be overridden without careful thought \itemize{ \item \code{\link{DefaultAssay}} and \code{\link{DefaultAssay<-}} \item \code{\link{Key}} and \code{\link{Key<-}} \item \code{\link{GetImage}}; this method \emph{can} be overridden to provide image data, normally returns empty image data. If overridden, should default to returning a \code{\link[grid]{grob}} object \item \code{\link{IsGlobal}} \item \code{\link{Radius}}; this method \emph{can} be overridden to provide a spot radius for image objects \item \code{\link[base:Extract]{[}}; this method \emph{can} be overridden to change default subset behavior, normally returns \code{subset(x = x, cells = i)}. If overridden, should only accept \code{i} } } \section{Required methods}{ All subclasses of the \code{SpatialImage} class must define the following methods; simply relying on the \code{SpatialImage} method will result in errors. For required parameters and their values, see the \code{Usage} and \code{Arguments} sections \describe{ \item{\code{\link{Cells}}}{ Return the cell/spot barcodes associated with each position } \item{\code{\link{dim}}}{ Return the dimensions of the image for plotting in \code{(Y, X)} format } \item{\code{\link{GetTissueCoordinates}}}{ Return tissue coordinates; by default, must return a two-column \code{data.frame} with x-coordinates in the first column and y-coordinates in the second } \item{\code{\link{Radius}}}{ Return the spot radius; returns \code{NULL} by default for use with non-spot image technologies } \item{\code{\link{RenameCells}}}{ Rename the cell/spot barcodes for this image } \item{\code{\link{subset}}}{ Subset the image data by cells/spots } } These methods are used throughout Seurat, so defining them and setting the proper defaults will allow subclasses of \code{SpatialImage} to work seamlessly } \seealso{ \code{\link{DefaultAssay}} \code{\link{GetImage}} \code{\link{GetTissueCoordinates}} \code{\link{IsGlobal}} \code{\link{Key}} \code{\link{RenameCells}} } \concept{spatialimage} SeuratObject/man/sub-sub-.Seurat.Rd0000644000176200001440000000465414520004144016610 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/seurat.R \name{[[.Seurat} \alias{[[.Seurat} \alias{head.Seurat} \alias{tail.Seurat} \title{Subobjects and Cell-Level Meta Data} \usage{ \method{[[}{Seurat}(x, i = missing_arg(), ..., drop = FALSE, na.rm = FALSE) \method{head}{Seurat}(x, n = 10L, ...) \method{tail}{Seurat}(x, n = 10L, ...) } \arguments{ \item{x}{A \code{\link{Seurat}} object} \item{i}{Name of cell-level meta data} \item{...}{Ignored} \item{drop}{See \code{\link[base]{drop}}} \item{na.rm}{Remove cells where meta data is all \code{NA}} \item{n}{Number of meta data rows to show} } \value{ Varies based on the value of \code{i}: \itemize{ \item If \code{i} is missing, a data frame with cell-level meta data \item If \code{i} is a vector with cell-level meta data names, a data frame (or vector of \code{drop = TRUE}) with cell-level meta data requested \item If \code{i} is a one-length character with the \link[=names.Seurat]{name of a subobject}, the subobject specified by \code{i} } \code{head}: The first \code{n} rows of cell-level metadata \code{tail}: The last \code{n} rows of cell-level metadata } \description{ The \code{[[} operator pulls either subobjects (eg. \link[=Assay]{v3} or \link[=Assay5]{v5} assays, \link[=DimReduc]{dimensional reduction} information, or \link[=Graph]{nearest-neighbor graphs}) or cell-level meta data from a \code{\link{Seurat}} object } \examples{ # Get the cell-level metadata data frame head(pbmc_small[[]]) # Pull specific metadata information head(pbmc_small[[c("letter.idents", "groups")]]) head(pbmc_small[["groups", drop = TRUE]]) # Get a sub-object (eg. an `Assay` or `DimReduc`) pbmc_small[["RNA"]] pbmc_small[["pca"]] # Get the first 10 rows of cell-level metadata head(pbmc_small) # Get the last 10 rows of cell-level metadata tail(pbmc_small) } \seealso{ See \link[=$.Seurat]{here} for adding meta data with \code{[[<-}, \link[=[[<-,Seurat]{here} for adding subobjects with \code{[[<-}, and \link[=[[<-,Seurat,NULL]{here} for removing subobjects and cell-level meta data with \code{[[<-} Seurat object, validity, and interaction methods \code{\link{$.Seurat}()}, \code{\link{Seurat-class}}, \code{\link{Seurat-validity}}, \code{\link{[[<-,Seurat,NULL}}, \code{\link{[[<-,Seurat}}, \code{\link{dim.Seurat}()}, \code{\link{dimnames.Seurat}()}, \code{\link{merge.Seurat}()}, \code{\link{names.Seurat}()}, \code{\link{subset.Seurat}()} } \concept{seurat} SeuratObject/man/Assay5T-class.Rd0000644000176200001440000000377314520004144016306 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assay5.R \docType{class} \name{Assay5T-class} \alias{Assay5T-class} \alias{Assay5T} \title{The Transposed v5 \code{Assay} Object} \description{ The Transposed v5 \code{Assay} Object } \section{Slots}{ \describe{ \item{\code{layers}}{A named list containing expression matrices; each matrix should be a two-dimensional object containing some subset of cells and features defined in the \code{cells} and \code{features} slots. Cell and feature membership is recorded in the \code{cells} and \code{features} slots, respectively} \item{\code{cells}}{A \link[=LogMap]{logical mapping} of cell names and layer membership; this map contains all the possible cells that this assay can contain. New layers must have some subset of cells present in this map} \item{\code{features}}{A \link[=LogMap]{logical mapping} of feature names and layer membership; this map contains all the possible features that this assay can contain. New layers must have some subset of features present in this map} \item{\code{default}}{A one-length integer with the end index of the \link[=DefaultLayer]{default layer}; the default layer be all layers up to and including the layer at index \code{default}} \item{\code{assay.orig}}{Original assay that this assay is based off of; used to track assay provenance} \item{\code{meta.data}}{A \link[base:data.frame]{data frame} with feature-level meta data; should have the same number of rows as \code{features}} \item{\code{misc}}{A named list of unstructured miscellaneous data} \item{\code{key}}{A one-length character vector with the object's key; keys must be one or more alphanumeric characters followed by an underscore \dQuote{\code{_}} (regex pattern \dQuote{\code{\Sexpr[stage=build]{SeuratObject:::.KeyPattern()}}})} }} \section{Lifecycle}{ \Sexpr[stage=build,results=rd]{lifecycle::badge("experimental")} \strong{Warning}: functionality described here is experimental and prone to change without notice } \keyword{internal} SeuratObject/man/Key-validity.Rd0000644000176200001440000000161414520004144016255 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/keymixin.R \name{Key-validity} \alias{Key-validity} \title{Key Validity} \description{ Validation of \code{\link{KeyMixin}} objects is handled by \code{\link[methods]{validObject}} } \section{Key Validation}{ Keys must be a one-length character vector; a key must be composed of one of the following: \itemize{ \item An empty string (eg. \dQuote{\code{''}}) where \code{nzchar() == 0} \item An string composed of one or more alphanumeric values (both lower- and upper-case) that ends with an underscore (\dQuote{\code{_}}); the first character must be a letter } Keys that are not empty strings are validated with the regex \dQuote{\code{\Sexpr[stage=build]{SeuratObject:::.KeyPattern()}}} } \seealso{ \code{\link{.KeyPattern}()}, \code{\link{.RandomKey}()}, \code{\link{KeyMixin-class}} } \concept{key} \keyword{internal} SeuratObject/man/as.Seurat.Rd0000644000176200001440000000066714473173564015602 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R \name{as.Seurat} \alias{as.Seurat} \title{Coerce to a \code{Seurat} Object} \usage{ as.Seurat(x, ...) } \arguments{ \item{x}{An object to convert to class \code{Seurat}} \item{...}{Arguments passed to other methods} } \value{ A \code{\link{Seurat}} object generated from \code{x} } \description{ Convert objects to Seurat objects } \concept{seurat} SeuratObject/man/dot-AssayClass.Rd0000644000176200001440000000077414520004144016542 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/generics.R, R/default.R, R/utils.R \name{.AssayClass} \alias{.AssayClass} \alias{.AssayClass.StdAssay} \alias{.AssayClass.default} \title{Assay Class Label} \usage{ .AssayClass(object) \method{.AssayClass}{StdAssay}(object) \method{.AssayClass}{default}(object) } \arguments{ \item{object}{A \code{\link{StdAssay}} object} } \value{ The assay class label for \code{object} } \description{ Assay Class Label } \keyword{internal} SeuratObject/man/intersect.LogMap.Rd0000644000176200001440000000162514520004144017062 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/logmap.R \name{intersect.LogMap} \alias{intersect.LogMap} \title{Find Common Logical Map Values} \usage{ \method{intersect}{LogMap}(x, y = missing_arg(), ...) } \arguments{ \item{x}{A \code{LogMap} object} \item{y}{Ignored} \item{...}{Ignored} } \value{ The values of \code{x} that are present in \strong{every} observation } \description{ Identify values in a \link[=LogMap]{logical map} that are common to every observation } \examples{ map <- LogMap(letters[1:10]) map[['obs']] <- c(1, 3, 7) map[['entry']] <- c(2, 7, 10) # Identify values that are present in every observation intersect(map) } \seealso{ Logical map objects, validity, and interaction methods: \code{\link{LogMap-validity}}, \code{\link{LogMap}}, \code{\link{as.matrix.LogMap}()}, \code{\link{droplevels.LogMap}()}, \code{\link{labels.LogMap}()} } \concept{logmap} SeuratObject/DESCRIPTION0000644000176200001440000001126014525765720014367 0ustar liggesusersPackage: SeuratObject Type: Package Title: Data Structures for Single Cell Data Version: 5.0.1 Authors@R: c( person(given = 'Rahul', family = 'Satija', email = 'rsatija@nygenome.org', role = 'aut', comment = c(ORCID = '0000-0001-9448-8833')), person(given = 'Paul', family = 'Hoffman', email = 'seurat@nygenome.org', role = c('aut', 'cre'), comment = c(ORCID = '0000-0002-7693-8957')), person(given = "Yuhan", family = "Hao", email = 'yhao@nygenome.org', role = 'aut', comment = c(ORCID = '0000-0002-1810-0822')), person(given = "Austin", family = "Hartman", email = 'ahartman@nygenome.org', role = 'aut', comment = c(ORCID = '0000-0001-7278-1852')), person(given = "Gesmira", family = "Molla", email = 'gmolla@nygenome.org', role = 'aut', comment = c(ORCID = '0000-0002-8628-5056')), person(given = 'Andrew', family = 'Butler', email = 'abutler@nygenome.org', role = 'aut', comment = c(ORCID = '0000-0003-3608-0463')), person(given = 'Tim', family = 'Stuart', email = 'tstuart@nygenome.org', role = 'aut', comment = c(ORCID = '0000-0002-3044-0897')), person(given = "Madeline", family = "Kowalski", email = "mkowalski@nygenome.org", role = "ctb", comment = c(ORCID = "0000-0002-5655-7620")), person(given = "Saket", family = "Choudhary", email = "schoudhary@nygenome.org", role = "ctb", comment = c(ORCID = "0000-0001-5202-7633")), person(given = "Skylar", family = "Li", email = "sli@nygenome.org", role = "ctb"), person(given = "Longda", family = "Jiang", email = "ljiang@nygenome.org", role = "ctb", comment = c(ORCID = "0000-0003-4964-6497")), person(given = 'Jeff', family = 'Farrell', email = 'jfarrell@g.harvard.edu', role = 'ctb'), person(given = 'Shiwei', family = 'Zheng', email = 'szheng@nygenome.org', role = 'ctb', comment = c(ORCID = '0000-0001-6682-6743')), person(given = 'Christoph', family = 'Hafemeister', email = 'chafemeister@nygenome.org', role = 'ctb', comment = c(ORCID = '0000-0001-6365-8254')), person(given = 'Patrick', family = 'Roelli', email = 'proelli@nygenome.org', role = 'ctb') ) Description: Defines S4 classes for single-cell genomic data and associated information, such as dimensionality reduction embeddings, nearest-neighbor graphs, and spatially-resolved coordinates. Provides data access methods and R-native hooks to ensure the Seurat object is familiar to other R users. See Satija R, Farrell J, Gennert D, et al (2015) , Macosko E, Basu A, Satija R, et al (2015) , and Stuart T, Butler A, et al (2019) , Hao Y, Hao S, et al (2021) and Hao Y, et al (2023) for more details. URL: https://mojaveazure.github.io/seurat-object/, https://github.com/mojaveazure/seurat-object BugReports: https://github.com/mojaveazure/seurat-object/issues License: MIT + file LICENSE Encoding: UTF-8 LazyData: true RoxygenNote: 7.2.3 Additional_repositories: https://bnprks.r-universe.dev Depends: R (>= 4.0.0), sp (>= 1.5.0) Imports: future, future.apply, grDevices, grid, Matrix (>= 1.6.3), methods, progressr, Rcpp (>= 1.0.5), rlang (>= 0.4.7), stats, tools, utils, spam, lifecycle, generics Suggests: DelayedArray, fs (>= 1.5.2), ggplot2, HDF5Array, rmarkdown, testthat, BPCells, sf (>= 1.0.0) Collate: 'RcppExports.R' 'zzz.R' 'generics.R' 'keymixin.R' 'graph.R' 'default.R' 'assay.R' 'logmap.R' 'layers.R' 'assay5.R' 'centroids.R' 'command.R' 'compliance.R' 'data.R' 'jackstraw.R' 'dimreduc.R' 'segmentation.R' 'molecules.R' 'spatial.R' 'fov.R' 'neighbor.R' 'seurat.R' 'sparse.R' 'utils.R' LinkingTo: Rcpp, RcppEigen Enhances: Seurat Config/Needs/website: pkgdown NeedsCompilation: yes Packaged: 2023-11-16 21:36:12 UTC; paul Author: Rahul Satija [aut] (), Paul Hoffman [aut, cre] (), Yuhan Hao [aut] (), Austin Hartman [aut] (), Gesmira Molla [aut] (), Andrew Butler [aut] (), Tim Stuart [aut] (), Madeline Kowalski [ctb] (), Saket Choudhary [ctb] (), Skylar Li [ctb], Longda Jiang [ctb] (), Jeff Farrell [ctb], Shiwei Zheng [ctb] (), Christoph Hafemeister [ctb] (), Patrick Roelli [ctb] Maintainer: Paul Hoffman Repository: CRAN Date/Publication: 2023-11-17 22:40:16 UTC SeuratObject/build/0000755000176200001440000000000014525505514013751 5ustar liggesusersSeuratObject/build/partial.rdb0000644000176200001440000016264314525505505016112 0ustar liggesuserskS6Z'$ @3 tFhهaEw}H~p8| ßGx/Re :ӝ D㟝AԿ(( }SRRc.خtl1s*v%W,X~ɦNж)sn7~^@5Q%TOEZ<+~D|?y8alR(Fu'p1˜ jO %o(7i5pRڱesQ IAB՟E"Yg {!&o*}H{[z0tÐ ڦFN؃pH/ hӺtթ"y"E_rU~muPxkcgqR,;U?/>J7+}d,of;vŶl[qʞWC@.#(=P裼qʁ׼:QʖD/%'̳Tlzt`r)zuBM9B~Ld_Kc*x}*'YYht@k?J>Y<716:n+":.qpFEq8u>ىFXc|N0( JUV}挀(ƣLI~y 8dsL1K<:ڧ~(Ԧaӛ}hٮG7!ol\ُ 'w1(I!, ú)bl:twZ:ЙQB;Zj1$-H~YiSU { , 9<%QVX[='ߞm^O+x%m@eث>U S5''_4PVjw_coA<$$Zc̛;97#ۅmX;S67w6-:%9yPp+ uENv)* UR< ')0)6XRDIZ -1޾uEkM;CkM;M:b!oZMʞٳ%QsO Apky Fq"ki؅; mޛ˞/م}Ԟɵv|sp2.xHi ǘA 7!+jI"_d): jrOT]7pEC~wPDU|(ҤӀ5Wvv_]xSei3FT <Y\Ԍì9no< 46%%}ܘCҵ %uВPx7EguPkNTpQkiٱ+~)TJ V79n7:ʭSg%ZYz$nڒLT p'u|$Lpn] : έBέTEͮȹB.%,#"%OErH)D ";ɓ89AJB~DCɩjIln_i02ꎄ4!p3yv4JNL#N3 VCV[cEKKtYZ.1e.EIK &=. xp[R̾Su N 28I(\O(Pk28I(KT%VlOUy,?o7ϛdyf~'oϳt\a H4Nt\aNAW@frT} ?:ZդcbH|7t*(vƎyVu T6>E>Af*tO4)>ҠgGߡ=?_lV?xr+S>S[1\ﻷ_~O :nhsgB+׽ŃJ}sk'{PvolaTSM t5}`HC5[4}z/57PXÞONOwTUg@"Mzj+ShV3ˆ->~{R(ܜ[Mg~GGXTW$K {J^;UV ;7[n[hO:lnGlHށć.ڰ lͶ[vO8ijHkrs x|-sv|- VY-hqTr+bG"iC&mY=߱^0H]?خf4}MSe[eHks,~ypHkA9zF131ݶF&c4k4)d+4iWP`?*4 /oDsgCLo=t[>?<1an񸙩Go|BX>y,#F`u]"OXAV>׍n=Zqw1{ocǣC^W}̆ͷk ?*Dߝ~"utm{?w#Q@~c=pPw,̦gI+F$ːuA  #ߑXWv8{e!]k-!B6O; ߌm5_oʹ#mGQ}6c 7A3xb-[FSj,gxE?p򆶍9?FcO_U!K,ѱaat&gw5f]SԬcR~ /R5_ˎN% nLLr^9^h/;+XSԕ^D/E¦SIq1"]\9nFfD; k A~ U?, ʱ ] (\`S,4kRGD1d.).Bh:QIĔuR=iPc(ZCW*}hJύ`"*X: zթc<"M%eK'?R޸cIfːVfz6qM@8qlc϶P=a={Mmi[L#plSϞA pg}|Q̴2[H1jqhǯ mDz[TZ~ѳ+p_*)T/C ~!O$Lv\.CׯkC1ϒTC# f p*mg~q|f޿ݜgi WJ!5NyK  t"TQ7GeFV+m %UwGj>EէTԧFuա wbAKa⼖5hx 4A f¸B8y&C | CO 1q$,-0+TD_WRj״Mv.fb .YS&Ÿ+-,K /GYS&ESDR5pr沉k e-AiACS?!'XS dM)H)Ś2R!eXXJgYSbSZu0Ux9މLpbv6:Rk7US?!q(N@G,4Eq\|B>b)##p5%3DNŏ,4Eq\| F>f)cc1 MQ;Y{`%a|Χ^ r( MQEIK ֔c2.n xpJQ N&l' ͺ$FZ3?Cq(~N>IO'pI|N>i3?ObN S8.>))i:ar} R>e)z8Z[(~lgA"bmJ)= XSbmD(~;CO&9(j )_ౙ a){g/;Q Oc4tz_,:HI^ rgӐUny+E. rF $R$YZ `$MNsQ 8&Di"}'p1D"8[ ʒ U^@c`19Vl.љX<ܔZh !t4I@˪c7 +DQ4IcpKR)Rn.CZEtZJgӐ Tb3~VɒUw4PZY.ۍF!l ݰ $_.dVr;bY5gv: . /i=B뀢xN,A~d7 vtz| 1SQ +m(%FHjt}fiYmz(L1d#*$e>% b>䋑![{jm-Ej &[w@'8_ bJ$@!| Yi"XNx+YJ*5E.l4l +-: >H8y\>}(XЂlJgaӐpid}WrEH[O=[_Z!侳<{-NX*w>NBls7']!&n xKT9-AV#nNC^O0@s]+\!i mmz(QON>j(還t_VX $ 4Qs焀zVjpʟzQ WMMKTɰ koۥ,IZېoQp9믋o쒂YJ{ϡ<ˆEj |⓼Kws<"&?TՔ%XӲ3PGs,+ci9xBd س?9i4p Gni'm5XfTHv%${b T͈eQVc-1މYٷ~]kn郐c s3)5ޱIS xU#sPPwDv i w,陏 -HbV7Oξڊ3&p|>IO@BcrPmmrǝM-5&άcLDS,Xh$hIr>Kb. Sr2jd-KJsnhB%aKR5UCwYkE;Z/sCp12#A*:SYL".W!j+B36&U)"Zk&@| :hH+zXF<>8܀l;%`fUD@՘A pw=tZoEƠ^0dZ9G TxP Sz-% ^ݺÿ=a_xeMֺ%dI7 }d*EaW8q͵[ods~;mmn;YZ; W3DI\aW tׯksϒT9e^.Z?[yk}ZVa:%0d!_)U76NjHi"8&_<(<1c|()d V =xFR֜bΖd}%:dE\#Uw8Yc؂Pëk NL};SCyd%FiN`W>YV]8u137NI)XV{j5EFzq*=?((n@ސ}(}(zTz" Z5]s(xTJ hK!nwGtաeU;1d_EhI0%DtV<4. H9BoErު@ve=1^PR-pS%Akru"Y-KB,9;hQ%FoЊ"r0`e&.v^#/`4ɱ2XyAcyv^+ CAbz0+&.z^%`4 hybvW@Kfv`4WY-]RH08z%C()0dMUpU܉sX-w\b Fs $LpUr $ZjMrr3(HTPfKs \ :R%KP1R; :RJP`4i5)$Mr 3癦#&yrIj?8JZ[}ئ T(ƞNZ>`4FFs{ܨIPȔd0>Fc6Ix4Xx4<0 xh> pmFh4j͓U^I`>"Iό)r69qD1d޺A!JAh: 3f@b W҆/r #Ɵ9YBk$Ɵ$m~X@Ce$m;A67EۄOm:9(6ix0c}_ npKR?6h% ";S,<bEvyujj-Be@6 &e01obB*H]$4 wTYbcӢEhBjPs+Z*;U+\q,rJaKlsq1w - c|]jƎcWޅ۠8Yg'WpƈTR(2tD\jg&<x 5s猂U.-Ȗ1tq0 Y74p aF-\رUb{-z7Jdr7 h$d5?\7']!&n xڶ~]u*\|YF9sՒeu42Gj~7>DZ<B[9JtZC%3KD>Z7Uy6["Po1tCm`.eFKPzC<,,}jӒ4q8 ܋|q7VvtV*6m*pM̃݁|GaWmUzF>LI^`; x[hzzW*z^>s / .><] v/i)HC}琟k?߱ M|^VЛ^QVCĬ[y qTr [Hg'7`)O|', [M`@8y&wYkE;P9LemK3 \ ؘJV({S54+z[hH+zXF<>8܀l_mQ7'$4Zcmi\z+4*wjHJH{!$'TC{,DΖ.xum;H5@ycw&H%oxGZ*?9q$uivfj.G[$ex}bvŖ`!`ì)z-5ƣ؁1Ger2^+5kr4Oj> \bB4{v?,˰->9y`kw{Թ-2tG=a\L3,ѼmO<n@ވln7!+r'H>* Jj?O܌,=Ř[⧧skA+Kuͽ!VYSQ^߫TJR<]^]伟Knu4=ͬks~)G>Ңsy41OMd_鹠ڥjS=(MV|zkPBj4Q_Qգ#lVE~9ъwc#})<هb8M"o?E`w(IT~Ffw.ӽn`?$(}-p'aoZ;Tv>WbCsXLM=IAkȯ`8gvxPpѹ](0dVA{:gD*DIz|ghv|3]` a&/wm}t|.5AV[vi?' ZOqMuⱙB?D7e;~-̮؋*Y _Ƹ6Wt 5&ˡfJ.i#xE"VQO"GU?& ʱ]Q[:aO$Xh֤CՏ b<r*U -$RO@HBT(,:X-fG{-p4ka,:3pb JMa6Z&,9(D /F+bB9_Cy C5:lipU#q־S+-ûnzH7w n?S*;Zz/Xtz^hK _<"}DdzSN3h3NJgX-T\$z/X$π 08n\dz/DDOj;E U8Ed;Ń韅[)͂V?p1P4QQV-1JV-r.&m5|JڥQeud<3A0<D.Ƥhߒ ja1 P]3H^+ȯzZ6\>W,b&X;WXОyO7{VUUȞ1E##{Vyd/:5-D'GX$tSG3R1}CvrĝcUtͫ;gLy_͟m" $펠cGW0䎜LӒ ezzwG Sǡ== \JT5Q =}ϖǜS(Q7j}#bUb%U{Ye5%>-r Wv00G9Wן%#<}½C_Ŕ}>hG &}xܻQh>CuG%Jr7t_*H㱙&fƓ2O7!Ҹy>蚧&I?e0e1ECkmp-ފ#Clq[$2ZG\3R1}XRySVCWit3H(I#wLcZ o!_lPfzl˒}Gix K S!IQލvvI@VX18Yւ_z? WyJjz7} [/ FФ&(uI>8H(=X;K~SxULC)ܧvc kT>1d$ﲦ I5G=DM$5eCC  i %4k M3)Me$f!$>De|z3+Vz SM~XIV/cXaQ{jH|!tAઠڛ q2T :k |P5c0$d; DŽ 3HXSITM$(QsRIeAR{82%U8 IgYSIMd$Mnﲦ 0$I2H !$5A ΤA67͓1|47"+d$YSv.dI `Hɸ&Kn8Ϛ2H*& u[֔ARQU$Of Z 5>cm]Q)xסǶU3Hz}?3C8Ě2H&}Ը zE-5^/ĝPWj?5!Mq 샙 i^kS3HS4׊<oőS& q[$@SGh2R1}$I$=CDqlD Ujߠo0C,MhBsK\ y`Hv.rI)u֔A2NC2H*tInAR7`fj8|}AԺ L q,k 12k s$IW)~*$߂ 2N[ 0$d\ĥC2HE\4p5eLʁ'DQ{z#$e.U6zE*DIfLᣪ|^EYf-?\}^ݦlgģ'xV$>AH uk*mg~q|~!JO7W,xg'?}y.|9Y-) ^xIӳДp R7|p: ?4? QG<H|'ݴI:+ڪuS^?AMT<=KkghG(v]XV?JHDB;L52S^B!ajߎr<B5 Zˤ4DX~OVl AVL!vϨ09FG(Rnff= bS6Wd ?؆IHqz.B^4kTt}ք5lь'C} i%$dVOZ1y(OQd&94y'q_# .IpusTvo9v;Tkt^S)7BԈM IXpry$m~X@T'_THE?륟 _vT`k҅jz5T/-s?oٛݻd,o}Oji.,ղG-?oզqiq:b7*Nb~u +Vh*=uPo<&a P]~vi_vΦ)fstxi7y Jz퇗T8Vj_X5U*vfSr;˲\O.uzQ86]ufp&W/Trya9+ך KU?/ wj+|@P+g*aN U?$ JۭBipRXx1ÒYs2,{޲6k3$a)S4 ChA7U?- R˰cCxfṬej'LD5E$*X0)tƭbP&!сYqyS%࣊ 4FbaS @VjֈQES6_%cOTmvfMB6' ?}?ĩzxbF=}Yp5]To@K.p>) !ᥤƯCGhvܮ'`ڛZ Ux+j s>nD^ȫF*O=)X@g(!Wr;'J!ɪj#oh8̿X ͽlcIbCϐlyݘNm> T"d~U`}^N/Kg[!5: U9N`Wr+s+)dB&縴e ,cǞ4 P6 ?AWwX4Y˜y<{[YNV΍WqHST9OqЧܭY.1p:o6R^Ii'G4kX!j|ݗUXD$yNSODIZ ~c]kkl';ExEid'5)֦:»<{F_xG?&sO$!w w?kR,vatz95.E8Yis~v H-O=1I1})t/ Ht_A^i6N毦6Q' JjrM`ױ/nQWJ#{ ] {ܽ|NZ~xZt, d%Թ YH& ՎnD]L9*A\@ێ}E]egɛ)?9z439?J;p됯?H_mQ-5+LҧJ$Iq9/^bM5zSB=bv9kyRɾ! %/oAgo݆|;ySwDIZ ~}(v[)۟e;EYܑ%J+=Z,iIArwtgd& S E@~`^`i*dh2\ݙ/S 9WNMZ=~A[*d6fvIs6r$eAO!%UL@՘F poD-[{Ck͠;H6LGCC<޴g1v+{ͱɇc5nZnd(+.ANl=)_,;/م}Ԟɵv|sp'.xHi oBV;:Ҋ'~ePc2꺁(ZmVb%@&DծU+WGpqv'{ſ \^|_.VV޸W`P OC8r,+w(e;߼I'u#Uw1#wq3=Zq{;?xLhe #{z-SSvIQ␮:tkG@Vo9ծ؂粹ʗDMUv}WJ_GCn@qCOˎ]qRD5Ū+^c~NĖ!U 6MEM5~)0<']/_%*xU`b.ij3 qI8 y2~roōA[iw(S- V, Zu.R:<?=@1ⱀI/AV?ђg~R"8E$?csbk7"8$EpҤՒg}UA4;7A e Oi3 2Ei2ꎂ$N4I8 YɽiIо}Rt \yz1$K;ߕtDZԊ_Z6fzhƷ` !Cɛ?' Z4}u4c~ 0>fl4"n=$;@./ǷAjc\[+l:zo"қN`Ջp"b螄A~I.EJZktS)Vwc4iPcdxު@bTQ[ňW!_MTT5QMա>Q4[熍xNbh>j:9D\`_dy&.E k\JImȷL6ԟN2 [Vۂ{މc\ A>q7p!ǟ"0K8y&E Yj1Fw(DQ)~kt6H+ ֣j4_> ŀ􄢬 Yێe[Z~VyHm'l.z, Јqj{H7!kmnI J3QKeGB*6e#mtxUnjhv*?WejNX%Wڊb`m՘V.*SN[GF'kȯ?6BoG/Ɠ]n#YHdf-Q@&C:9g7նV[Fx*XC^O ?J ǐkӢw>]KfaXv6\*Nٿk A?+J@᭮!#ZS (-5[r&Oܩ?}̓+WU#4RuQ6ya!b|0llS?$h>||V ޹u\PȤޮMj\%iKzع vn>ߗiSG_ئ}H|NCzgP=J |ul[KIXGi v^[yZ~ѳ+p_*RNWw[ֲ 3ց/!L C*U(Ib|6 Tm hnHGC*!<'; ʉC=Y涋CˋNAu=®XN!/CA i?@ʚC,1%;]TI __ \k};R%8yd%FiNUfr.%`Jۈ]c0c{eHN]e5bD[6tyCi&򫡄7M)(j=H <4L/VC(CH$R yCQSß8kbMq,]#ښfMښı\)CX>R-lű44O_1jѶBE4E 3`aHĘ!qE04\bWì)e\XbWZwhMeMA,(BX&FO|54DO ˬ*$e\\fV!A,2xBXeprLˬep/C byB[7Y-(k bAo7Yh˸z;d-#{"^r%+Lӥ 849+,4B`bkhZA,o-V)z ,E@l-V byBX۬UA&Gobi:b8# <Ʊ~rSɄ/!/~Jmxzhʝ'ЕW!_VW)t5I6IVyCz}TT!=~tX~$>ŐMAZ-"UvY5!DU@Vk -P6lQĘZ'bLAj͡e~H@CV9YEag@B!VrV@CHx^䜼ǜR:C NA2h@bxP p覊(FUZO@Vz/frV;-=br+E#(=[D&tv>e'ozK]} 40pi]1d _ɕ:5tx@XM <|0DK~p:oS>sF@ ]Y*Koq /?Qua*rqbCkf|έxJQdi\vx -6kZ}CYUܛ( C}ohClYg'WnHwWk.Yˢg-Xqfxj!+| b+)5gx21'? sVa:eBr_r0<Vcyj\nV$3MMa3(bi~ٳEÁ} 8 *#7 oÞz(sfF`r¶aPbpGİ&Iab䇑>w?U -|]68MBM(U Dj[dB;5`,ofx#NCV?ŎbpY0( ٧Oe ;^2o^Q:*һR)J,g.};?xie2i})ȩa;R餀(I{3x&zޢ! `#`C4C#:2x@%DT]'0$(J\KMHT )&4Y<4ܦSD<0Gn!~NBWY-YJ#,}*pեM"T}(j ye*d g.9?Ξ+;L{{km{(W?!kkt ]${Z-*r;c"8j[UCp'iPD9! xR }M*L2T(,3"WZe[O2_*.^#uMH^T(JU VU+G鏎S֭&>Yf>TU~BK/ Z ʯ4,0WW@*6,0%nLZY.ʳ=LGQmX%/+K7i)<5U9+6asƼ2gF4 ).9ЇyV+ɏ[g#=kd@էԛ N3ሢ*3_9SmI)ލ.39iJ\GfKm6 Yk]>\[ aaWJ/8Zaa]÷4P)Ɲ]܎R{Cէfz;8-5Nb1;*yIF #ȏT42J.-9|n;],.JV]3:3Q/X}Śin۵?5^Xwղk?=v)ZkNn6w[=C ѩiU$]=9"n\,춡bgب@h:pvaX(gE|`Oj  %Ԝ(mD\QX%W[j})tS4֝rzy:pH UJ;iS"t_A3F6?@!6{=ǖBj _T[Ea}ĥ壏/J)՗zZjkh#_ԉ'YZcC`Jf?T)4aH0vB Zm_ ]=-NpTAqG*3jRXS[M2;CO&3G/U1:  Zaa1q噒q4g]aߪn75Wнr[QgK, 6P#t3Id`fG2ĚΈ]E/, BErRz+,!{!IߠVɀa1aUiaN ӡ?EU|nSPqǒInYMV[t]дgYmz"Fw?DQ)Ꜩ+UI(حdT }!wux im;*Fko[p_*!3"' ~! " *7NZʞLq5鳯_oX1UYj%8ZEN!כoFth°YRVsnZiv %妉rRעN=rYiFn!+V"f(U8j׆&XmEt[%%]wh!~sŒuK/a=+CR oDIzH >SÄTP hnHGC*!Au惫N!k ,>dR|5'E54y8BpD{9*/c|_ \k};\yd%YZ/\ڴZTc_Uod)XV{j^:d!UO*x=v7 o> }Dz!nZXz=e/=E9Z# 3OcJ)r${j:a4v$T"`w2<1]DR1VK=TTO]ճu`z9nNmKT.\N@0Ϟ{oR&2UCa֔Q8.zcB2 'GqqP"=A=Dž"d37J[/EM\q3CL'Iϫblm̂_8BTP)ս"!a$t=d 0 +LdIYŐErlhS0 4f(尋 S0B՟E$hXxlƈ"wsG!W45PW4L\xj=_ߩ omKj^eTqMF5]eo8Wg!IF U?, ʱxGd& 5xGoɫiQ ЋF`"FIYCQ R^(QwԒ15K2E6dTfG2kV2BfFtr,)`خb]3SEUtCn stN1N1okX<18HT= ŪY)&/O8 y:y+((Q}Tu"_ 86Sԇi|Tg QQ,<s Ð:{|+cQ1_"D5rNZ^l|J1Hېo"YțDԪrsA'24sU9D>t0ː/hdž "L64`$#p1Y ͢0psh_{^DUgR$4ԧm }m:\Ċud%'D]'" /U?* Jj㛋N>j< fRq]].>9DR_G?:_d\C~?37'R%i5y;N_˛%~HrP,Gh_ 3Zܔ K+TyQV㐴6d!!UN!m]ɂ4cr}CI'E~\@CO:P۹9CPoU dQ<6. #7+jIfՄjLz&0 dl2UE'u!7O@Vz/Ysrʁ2g7C~kV\:)ܜ[q ٧ ~ kٟrS2 4 C)71( J[W8 1ڭ̂QcCi HFh GuX5bt44V)Lj[0xͥAr_Ae|v!wv $'A(h+/N"|[&d(JuXj[bxM: Xs~h1ei3i20O߫$0k =WAU;9zqs\e&Osc6䷟ÊJjR8Lq #%eջqB[ kGZ~tsSh S H0$E| ,4wRD1dߏ` A[,C7 UN@hTߏ،)akE&-C|5!r)J~/N]Pn6ۦ{J FT@(""JY'P3!\cN$A8 y8yP#6lih`CVjZ}=N0|Iن( ! yfW촢ypߣG0;dMyq֤9_5EUuZoz%aHV DeB@cmImb6mٱmſ.Jy: &|ƬXF.7xTu"7ɻY- xHH I}- gW%aŗU y؈Bqf3Ũ榃Ԝ4mH VKL8"=NEhPh%M,+O̵-n.z 2N>*%lTe8vkmCU7؎ukE6`#拤V) k'hd(2E}#SrT|3~blԐ^bi)VO+48ŮWSB@Y?kF&'60_;!à:a侶~"dŜ,텍S1&eƫw#~o*& ƀ!6p ͪ&ԙZQM ؗ.plnk+@'!5rhvR]fO%i5],/8Jr#Yo}n JsA*ވ\,+&!+bQY8f9)Q 6YNJ 1k|T*\TI%'@dBw¡]ѿK'.wr%]r+ifk^,ov@5ݶk-~jGvW-;_Yӳ?_kvnv:OoJN:+]=9"n\,춡bgب@h]{aX(E|;~y17Qy!H$=_3qgWH)L;ݬ)=ɓZ%u,rlGud7 Hͳ@cZݤߋgU%i5 12PI6 ?dlU>9Ԯ7yKvhQarB>,GnbȔYE?%i5h1  JFJ5贲cNӳS,xyG,܀ܶ^fʖ#.,I5nedM& ) vO0ps-"/B6yT:2j3UeoӘR:{>UoFcE0YbM_NJipIa(Ǯ+S| c.V􆺦Xzuv|%snVt|efcULR){[o(C'%P^G);yl9ʎVK7"µةW۶@{'1ck߮d<^e;7~+c{SV)n3,׏jSSɯU* gw!u6ڹ31pL)[a]u`Jq=btD;wx{?Q\Xm84njT[S-\oBmDYVl,/a#SO}3ϒy$!9T4Wi}3B}mZ$BX5L{+)3jkB&DeFmQ.YȳfVZ:0 Y鍦Y. /iexF,7!oӅuYYq=o3D!'p9XSf;(I!fz1?wɌ0 ֫Q9fWR(J ޺wj+ע4oEN%&(=;-2 ?Jl!?N'Qz-aJnڑ)T}J@EFtyNEUf0,cXp1֜ŕRDGq_8qq4SMD>[p5%UN SAnB՟PE TJOLuR%IyZfUgUإU鑆ɔj#C)smxj%AȮrB~XJEA SGɵϚM]ur- @H(T(6 <k ieYZVD1d3BI镆XS"W#^Rv b._>BB^Ƚ Dب {I b$d1$T6$TJ6$TҴ͠L:b5:bQȣ[ŐubbnVKt5Eɋ00yjûawD1d!펤qz`Jcqz`IŐq4YIΰ;5GL%O&,l9QbxF5%IjaG5~X@3VZQ9c`!y[>s]@Ek-Ul,1WR!؋pd|Sǵ9jkmhC2)dwM0vfâVnVbI>RIwX/FZ$\d[g iI18d5LFf56+*Yp N,2b.*soLGF^,(GkD6 SSm,Md,DF&:M<&I>,)7^x=ղςȄ}^#,J[#m^/&Sf#oї:H}D ̎_auIҤzq=])Zc<>E= { hF~ÓQUe~fW_iuVmWե|n|ty1N˻Kv~.{q4G]>bMiZ/qUW֯ڥhh[;]o|N[{SΊ&iWO[) mYy76*'"Ҟ}) GG NnJ?&7*c>)Z@x&1QJoO:OoOz7XSz{ɶ55eEq_edAӯThNe+w Ia`Hz{mW " aH\.2Y6UeAkHoOYSz2UTm Jw OUJoO* GYSzzK|% Mo_ !UoeMoO]>`MbcULR)ޞv37W1*qjM\dMic.=״V_쫮e\?~!TJ~J՟%i5^8ƴ3N$5{ ]0yx+~Th\h}^3Mțʍۣk,x7%y[Ќ9ʅMʺ[pPn(U CR)OX]pKE7ihT`g"ը.vz ܎Jr[v#i]s%" 㞌5JoF(I ߡ9;2('b}~ T]pi& V7z~X b7[5d~̕B5IރrM=D߁Td{9;<(@uF&Q #M,H !m=F`RmT?nd^c[4L5T O՟M;?8tV/G-:7?NK'q_v o*Eg~Y< {>IOvQ =}ϖͯ]g'̟3z Gž7_X]pTOt?+ >a?387+L(.jBgt,IKJ@:1K!J eX*&V~AV c+ḥ]B~]A~C?%i5~ YE=/c9[,L {!O-4a>mV-IPdث6N@00~UT2 v{VgtBN`AJ~ 8t[yd/0 օ9fե4ɕ`1wj+עSdފ,I}+힖IG%c[ǐ'ߓ Q =}ǖ0%7HS`ǧS(22NEUfM*6,F8ykՂs5L{_8qq4;C;Hv&㸲b<ƬhSD|ƌT(j ~ N?THIh܌N_/V{1Q5Bz5ݢ}T/-s?oٛݻd,+g}Ѽ]VmWF?h9X_9L/V]jeN6W_y_:~aT1C7+7 N7?|b~ˎ5@_v6uk]0]j6*ݷ^14VLnG{yd>VwecM=1;9 }Q@Nڰ6wzwl (-f7]6z\_:^gm  9c4n7~^@5B#',",YO릈jOH9)PD9v r^Z.[v>gJ>cby2 UA@C|Kyל[q<7?&aIj{"AcUr|X/: qtݎv 86WlKstzr"eP;a1B e5QDBWI+uVUl-ObS\b.]Pz`SA/cp䉯phDIZ3hݹFTM;ݨI/wJY&re0 ]zzq *T}Mț3,HE?ӷ>؍@mz'8RGm!u hƵy)_pWصEoI^NXv;UVn0'cȏ :>QZP@{)5ql3YOثV>l% F8 yi{2^E#FČtTOx۩)n& @j\P}AK O;3u0YH%ep[;8>8?e01ECkm9ފ#0C]k8q[$2sGa6R1}B/@?%JH9QܫmN3,le5٢vܾSx֝rzy*c\i?T=܀ 3p9ovWW3d_+QI]i2"߅NCV^5}s'pU9j/57/H5Cxcl׵3qlRpx][n0DǙX4B*T_$kq Qo6;yTu"{;#`CQ={wJ| FA:FvS SQ-buS!I2 UA@4x6՘eea=ܼIZaS_SUvo:wS^5Ah;t:-Lcuç2)=_EaMݑz n zֹs4",ۉH$P}w[6NGxMՎg!6b@ /Cݗ;-e^ހ|`D\fްM3~Q@3*N;R¶(\TN5n+{~yژPPU3Tl2)c@b;E )T*<LƳR:׀ 3f[tɣܮSL dgy]H֛ |&9~3 @6iO|Vܨ<,TYmD؇6dKJCƚi'@RQV;?*WKohoXX܏ {Nnh6)˒n4pLހ3zv3\IAJ'Uwa&nh~ws;;*v^|MnMۓt>RLiMӾ+W %$Τ-]w$vS"GL| E,PO_nI +ȯzEmA^:+iteǧSۮ&GVы{ ֹ겊qwI 1J:-Ue^R B"Y<]Ϣ|/pvq7wCN F`h2Ii4_/zŝb!2r]YB6_jku"iIˬSsyo.T,I]7jW!_mYކ& v x&LU ҨRTY2.wO!Q˂|YP5XzrPv֓S-\R.[X) |nTgW[8k`r.Ó5}OTGQ =}ז ~ lStY(I!, 5[i8# fs;^Ƽ̎;`y?t*/i! 4av\ҖeZ*(7 ,/j~-Ȗ,+u~⎯FЊ64#p_}o.KhD($鈫;G!l[ݖx+ %gjSq6]r'xS>Ϲ@S%KZ_;^SgvŞXf2ŃBŝQHb ק5hXlw.ZcK[ @eB6o!Of^|98uY?dgI|!O@IOe^]qK?Y -A^@ե9z2z!{G(ĄJP7GC/3Q"5{guNɀ?@%B!CzSbRyozďЌp Th' 6E=>G6dڶ3R,],†;+D$J T#)׻B=2)tPQV'CxymNY?UB \gLoY`>y#O8Dj7hEwZQ흨%4Y{æV۹Q7G3|_.S#e߮s͕[-_{ +m< X|nl/sG~"9 ͭS=)ghuqwGE]* QL[.H94v;h/٥م5y&t{oXҞB߃Rɏ9n>/G(Hx7P|(@cPJw OfGeNx7\FhAڹPly'4W3*'LANausT6Br~KyXUEj_`)eKC /GEuR,"Zn,9JC8IMvC@Rs󲽅5~K?;|ib9q].Wi/UKK廥|{do9;K 0AYڷ Ku[i޼'jzl+x_-X_vʪ-Zbr $EЩo<(anrr۰t0/q._\egSw{^f\a]0]j6p+ݷ^9STY}QOce'`GYLc˲uSuz( Q@N(w.~S5[ `_+röՕn5( jMHam  R Ѩ†geC} Ee[AM+B,B[rB? M¿ o:}h`AȃZ ] s3| Rz dip?8@_ ?DvShiUͷHSjJ->izPf덤ҟDQ@z-̖{ǃ&gwBzE*)EP:ݒ]volKR {QV/Jbt+C q(H1;4kGANzFZĔGqzn(QJDiGq_1ʎGA*ǣ{mM;)H;'߫m=RcN@3{HAbSVoeGq ed<6k:~dQ&{NtleߩW pyH -ud̕B^6W'n*f yS0LΗJA~҃U\@63Z1LbW/I40aZv_Iiٵ1VğNcJ*Ic:bnD*g466Pj{YaU7^#L&,q]@6:Ӡy"ybj Q|Z"_w-Dik1&ϵ;ĵ!\c?AV"t.HiYHr.fwCLǹ "oҹ<1r.H8CG[ $5a`.E^qK@6zWB^FGOؼ!P El`r&yO nOC[q0Oa,w9)Yvmp9HiYHr9sCT.|<;v.0B0Q*\dz_Geu%Um9R㲀(SE)ْHBh檴+B;0=I%*U7dcFۤF 愆p A_LZ,oC &Qw n K!8V ޠ;ʨ,Bc X$"C?)3QڽHH [$D.0ɯ H1wyֆU; 4*0"Vii=n)gU@*}%vVRJ@UT{Qڨ/ZFqT_BiqQ"}\ v^RDW!4D0spUB՟E>:-<6SBXgnep Twp]bu_YdWrv-fG? u ^;B׵UV {C@5BL̓T"XS1czvK鰐I|#! 5 Q Ȫ( (2pzl4yPcmG!+5S&ATc1,?.Zᗞ86V4Y<1qCtc3 y8Q f=cL=0  &,<)QM}ZO@V9ELԄoai(A%rOgC68G p:oߨ(#`p7jAM =ч:CT1C[{߱;?A'\5k{X?@AoJ\ћ짜:AۃG,Sg)crGtN Q@PBh@ʜBN (ȚfQ2jQ3G!G:8HTHZjIYGGz!_?B!8oZłw 'gQiy8X\k5/T"~;mmn;~MҞ]83*//~^x/T⋞nBHzY(Uwe +Q4І!4`͕]WdW$J!4iOo\nqGXmk'Ž\ H񢔩|V' VA<4RL@CE7veӏdV:ZLANۑJ'DI[3qOC{(Guo^1+6BZ)Pq!NCV.1L m^72l+s+=Sv~+{n]ȪD_>H[R)TKtB0j9VccbDW&n0% ZHřʣ Y^@[m ʿO8B͆&OCO[wtCXub J!ޣ1U*M&մI_ s^aҖD9^D}ip(LM#iV;YiD4 b0pC(O݄oealArP<^}dˠrvwtVgDQY]u9*1ݍyL9ҹ!C#X]Vl?mkEU_ӹ&ؼ%I'OM.׀ VnD3EK` y7@q)ʩ4%3|ti߳v4-k86m1|riLK[Ϝr8JyO_@~,ݴl"7gŧ;VKffd566t ?Tc^jq7s [ y3 pZV?eYsPb"%?"_6G6HפS(skcgi}w2svP}5yCrQWj36OLȲ: vr:USu2Eyشhs.#E7jR8ؙZ^ /"brЭb6`\cA濑8eŤ}-8K~c0GeiQ_ w57wd;yؚp X&Oǵs猂U.]?_Y3X0׀id 3 \mQ%!m=8*vl!侳<{팔LUIȓmͼP:h}B@a",E8Țnh^a7w% Mڴ$MEz\C66狻rطK% rW!6h{o쒂Yȳ7}; #jҫ5R.gJ$/RjZp#_z MOoJEo]w_z (죹W.p[suFk/Gf sϵXfTH</P{b(T͈ZIZ x}o="n?=7Su<.JG |"!3# ;2aUT'g_mZu{ U'i kړ 6OMJ hSt'3,gX=QDT?u>4R]TGHm-g_{?,)=|Y߇YRɮMa du{w'Pen7 h03Tֶ4HUȫʭЌI~ >_@c e4$ c=@u,#mC~XFn@ވl y3i" Jj\A pw җ˹V$Ii vjHJuG +]bhXk-AIuW ̸mN֛pw&k]z  US k5:BrUZaAt-QVc-1ap(@, ]_N0d'#=FcN?5r^+5kɸ4PT5.1C<|v?,|vzh;}/zd g:#]\8]3?O3tE+oۓ:7[MJ9/ 6TSQVZc']jIu!+4 ±TwR YS.`CC h2/怷!s 'K&?zQDIZQ?ݱ>TB.g/X<.X|.|Y Ϲ3A[H5Cjm蛒B>FGd{Eu^g׿r#ףE(8- ?%}s^|8=/yL -]U>; !+Y$aS3eR8{7S!ęJ_^|͸2X jgI5WL V?7KWLIȓc <rPp~V,ص&&8ˮ meIg5P,?o=2?A^U!8OˇL?x17q~>/ ' +MZ-y6W%:HZ)י.AAu0eL)r])Yݥ bNBVroZt#hAg|uRR` hAg#0pR0իJ(ݽ:%ؗ1A,4 d\x N|Tܱ$uAV)taf/_2F]" GE Dܼ o| B.weUs`ehDƽr7}3 v%.T3gxYQ =a*b-nKB@bVmRO@y-}N6UI@m'76Gy{OVCkV {PjS?9#-5H5Zuo/ꝹЎ@VZ*:v61& _}ãZX~bq1ּ_?)AG33Jy͈z+5]XKI:dž[$87nH0b?U;V6 _|J 9iAV4kd V tսT{!+`V"NU8jY'X]~VEt[Rj%]wh!~sŒuK/a=+CJ# JCULxHjS@sC=R168ᑪ><+B'Dkv|(^Vyѿ}P*ybv SȺA0`Z08pHR֜bBd}%ԋ%;]T!5-=vRʞ^sk~ޡh_%- +7b5OCVv2۴1m߮1q?V"xOVq m0#\6m(n@ސ}mаmzTz" Z5VT4L/7SC˪w$bzG=s ;Z |7 @IP*Sc -ьӒd) ZĜm`84F a7UwO)p8ʚaͧAh/}njD0DO#1fX-ڸ:j59yR&sȍո*LBa1c*sʐWARYВ0n\e!vb,@"1fPL+X>`a[XR"0)2(ywǁMWXhyBN%+p*.~YVCN%+%k`:ZאSq*yeM#UVp*.^)WALwSk,4T\,fT c)O˳N1,S YJIH)C@9p*.΁s, U1Ms=ƀSI908I,:EJ>pv#lnm`&Ԝ4{H+h+c7 ^V7dh*4h5zAAȃzYiS^~(BC**uβ~)‡Hi !~΄f @jޤ,`C =6E&ڞpl4:wXjL%8Lv"jSPV(s+WMsC ."Qe9VMKC՟%i^XzaGp4;θJ.;b1Jd{ U_ݎC6)Ko% .]KLvJI~k:dӂ*6F Q v\Tm Ƒջ؅'.勲d#RD<1yB4L z9]=|ͤ cW 0!BO%ց!?N"w7-rzUnC~OK3I}LAN#) AVzg.$r > W? omz4 *rL)S6Md1pP|pIEl!CW.X-9]zCɮ|net*»-Ń݃|ORdIޮ%e_@~l3 M۵WU1eUqYGw hzYg?z\qlnI]]Q]̲NP$1X5k'b9sH9Ð!+7( <)):øPޒQݩ$930==}:_Yy''aWjB~|O  ǒA/%ol5ox^E7Lݚ8~IGNEw`L¯ <DIZh|paqoA`OFh{j/84Gت=*<'%w|n;],.JV]MbD=XDdbkOcKbZ/7W֯ڥhh[;]oN[{SΊ&iWO[)\h^ʻQ>LPFGD\~z?&?J&QYkբkhh,To1 hBscmbOXIru}6 w,̝ NN1 K"%h0z*+ׯ㘬)Ii Jӯ6ӟZ;\SIu=צVS~|IQ4[e+W(^EX$ބo5Mp:p12Eo@V?D&)dU?t‘^utF 4 )]"$ EFeCj!'cՒÉdTroSDC pa&I^/Kf8y"~QuIȓpZ@x/@N`.B֟+=K5 5d=[TʹL%8jpu*¥C;uL9&oX[WT}J@CaLfYSn+y9_Z I=PDQkMucLu8}/-L9FLNT_D2^.xr& d;4 tVt+  Gopt"#d7H$ VE[RۄzC&9(lrNj9c3!92!953ԜY<|{~'aHդCe\@SY]$Nr<p]Y'>ŐMw$fڶjLӐWŐ _4ݬu  ߦTo*(HzT8NAV\lD[ĸd%$ 8TgD15}D0ƲގrfD\%[9 #fQՉ<+: },炫 [/6_x`yi׮a;M2RQͱᨨj5 5^Vl;h[ێ:hE5p/ Jk{ &Pcus4jW>쭊LdՄWfd͖"wZQ,VhӉh^LjѱKv3ŃAZȷi8ܹ-1HeS'&)C  pOtAZYVSAaB2t!v4,iń:첅bVnPj|TkֲCzB|k*fUاiEs29x ?ͣrT41Q|sڑ Yi<78.@ &K2Ţ03Y=[crMbnrӞCP%L!--_Y57~5U볂L֦RPP8Z9?(8)7 .z+Ў-(pX._o. < .@% ܅yW;7uS!8|Eh.q#琛)-~w!]nAۺC F9_ff,X3=0߄!Lڷ#c#`8|uhGvx=F6P7x&;+-w!+3?2p|&EhnTH ڊhLO榿aauʉђ!F0S3˛>۔ Ty'&4w<#ll'nl'\mlus+qR.Ҽ @>}J m]8WÛ5ۅ6F5c;ac9D)ȩ6̺Q79Y0YtZ,Y73u7;3RzSoEj/ڭcwâ7}mEf݄#bNq9E$IҭȂLEթ[NݛKY~ds+[Q `Q$F -1yCտm_Nce(])Z|>m(-=Bf6kH%w vlT<.ڼbrT\f.G" T !{Mir,>{I?`eEױ)}cUdj!VN1/~vWerNBE&LpDѝ;,I5&;S)`d5R+t bh9ɕ9!CT* vi$͋O#>w|Bhwq3:S,+(6tZ|B 1-y49f#U)ّw߱ Ov9]eg|KI 84o/f8Փ͹%7!L0pJ s x-tJTRPh,ryC"y^vZ!6!?'%K_2FSk4:샬\TI`?_9(˟s5@t} *rL)S6M 29Z6Yqx:IZ:&$qsnZ:N =ġGUljͮW RB)%(P@+};JngF~7+Y{Fcwֹ4c(I]'0 9_x _DZVU= dqwyOm>L#õd1 em-d^5!ZmF:ܭ#6vH}Fu<6S֑.`r:8!;ĕ6C"68'ww'w * 8 y8 Ӗv-J*᛺A! _uԯWf| 9Eu2feaŢy{y -.0YcyA%E˳X* ' OݯB~6}ZSJیo#8k$ {t&ܝ.,m׫KVfk*UMf:\FKE~L@\i֐_:.i0J"M=ɺV*x7W*z}Mm< YibAou)fF@\i]RؖDROgm qp. w6XdBR/B~T 81RV@\i= M0pXB;k Xn+, V\'=ov`B!{xfDvv\c jUR{ʕg@~݄3Z+GTk^yww+\=@VZêzRWf9E?@MIE&;5k+7lL惣z5$!}%>YJrd.%<\,#ĕP{,>gEaxkF:Cpĥ|}VqĥhN?ŃkA?DgL,rbV?Iy9)"M[PBol7U9 NB6<[+X%('kϐYm~*<}ZSxrl9A)@\ck,<Y'-1Y!L@\Yy.+C~>~Kddٔܮ)w_"KMȦ@Zc$@kgPԺ~NXzԨ$]ҦVu:̕mg.CcV#sEV:"62i֞PĆ`:#.l99bR灺0.8לi~2/UC{Q: 7 OB>Ch'+愹4_.R+`V OrQ j'ctsL&6DTYf$` (zϰ0jrwի‡wvߨy]KxҖCM9*>Rm}*/xTOetL;+ 4䜳 &oFp\Z8n^b4>=Cĥ[ td*'Fm]Or [ӾȮ-$g^y)?w/\/;CG9xx.Η-7nҏыS0odiVmPZjm >x,VLv"0*s¹sϝ"P{u6_~i&w,p;^i\֩W "ŎOWO ^xq/ +Q`d߾hy]u~W)z2,z9%{G.[9qq|VڼXX) Qrԝ_o[[yv^k,u%̈03,f['m- 3$5]BΦ#J.`RDj]?g+}XgD~}7-!q%Y{e3LslSn!n4Ѩ"JQ #}RtQvl=\1tR1[#1 =FFh&J#quML#]g&JrSלn1Gj8J%daQpH!|XOEQ]rw&s_ }Wvndl0rVP6eqW  q^~<^^k8sĥ JԪaM|w{ p#L9Lʕ8^SZnRf䕴/ CNH]RĬ,m[[!oM01YPqȏT 6۔2@x)ᜍƊ[EPQr zm 0R^1^1\dI2 Cȫy%nj!aْ1V|U5Jg~J}\ͶRSc:R!^3'kKTk{!&ax+R'z ǥ%{fprrC]s(7+ը`Q}`zO>6 2"?Ḿ':7N[y/ jszC@+o6n7?y)OӂK^Gfof㷍g%ih \n؁gEp>XBɝܜlhND F-Àv/J㿜! SeuratObject/build/SeuratObject.pdf0000644000176200001440000146301414525505514017047 0ustar liggesusers%PDF-1.5 % 2 0 obj << /Type /ObjStm /N 100 /First 828 /Length 1379 /Filter /FlateDecode >> stream xڵXn:+lER(hP Ibl5z\(),9ԋsOs1Ŕ`d1yȸDŽLx/ |GL> g ƏY(&< X2!*ϕ$ y$| *k 1WyF>IE3hI  / )| yRł `:Azx8q34R|R&)FYA)ąO~ cM0$0 1)qS=d N =OQAv!=oၐPǁ%dD] 0$E"H=%Fd>pAR/[=0JX%l A +vIG$2 v&C ,!LQ: wRD$kGpeQS7%n(.T(` (q&@7ݱ{ΖC13J7U3MtoQ͜d?>a_;* ;***4 ߨ◭_bk[mW|Yfntng2uiS"ocnֶp ۢZPGp$צK>mS[\[E_vU~]h2M>"ݍta \R+v]Vztd 6N,FȬ\7Ug~UvK[Yl++emS*nLܗ76 VN'3FĮ;Tc8kVkثm"|hx[gi6鄿;Sup1+y܌bOˤ+WMWٺњCtiGvRpa0uSzX nyeg&j'kE0mųj-jjuLwfܱ+#G:,G&k)ki6eN:hc+Qz\8l;GYY ]齩jڏN½ޔ:v2<ϧteEfMs|rw *zwAiR+y&٭NMr}~Hj:=;_.1}]ff 3g9MZ%Utz-8AѴKQP^A2vy2M]<J'I2yfhצ9z~$NnM f }{OltS4߱M7N/|3^td=v ~?t$2]̑45W5 endstream endobj 203 0 obj << /Type /ObjStm /N 100 /First 879 /Length 1494 /Filter /FlateDecode >> stream xڭXn:+|]1z^ݜ7VAnl#0e2M{QmӓnӪ ?ʭ;86ysN-o]˜á̮__C_~^O7kkގ߽ni7-65ih#zi/ŋQ^ө@jq y:NNi{SKUzjMz>ԙsu{虽/c]VNi{*m7xg+Tۻs|UEרR٥_ WG 鳫]] Ԇj.6{Xm[z< /½vf7CɽR-{}oՏuK^W-Tgw~m_͈ zhлFu&?A`ATv[[ZTA{m}̨k#߈b*wLI;57fӺ]> stream xڭWmo6_o&b+4/Mfa%f")uN"X$ (sx~y<(%A F~#e:syB&wt&Smu˒_ˏbwj=~BiyVs-&vŤEcp֪Zx SGà( $ƻJ{"r]b7CԔZ#јٰ9|SZR࢔URV)~#  3C{ezv:c&F7D$}4kKD|Ɛ! Z2W23ɨRhQ -Ӥedr~I[^iR"di԰xmNU|Ar$Kjg:*%g.振7+pFג+ТVY0!$X;"ZH[=xS'MJ}x#ĝ+6Wfoch*^s{MSU'@ٚG d.qtn8,ϙ4N&3} ·';HFu⑄6@HC UU\;؇3oPw5!3鄪Jޙ>??$ݢ:P-0|m.ʊZn֏ zQ j0An,a:`:G=LGp@A"DnV" 2cO0^0*̯:2g035Ժ{Sz3m-g;T&Z!.fJɴJ^ m:vE Jvg.`ZY!d^O#q*^1Px݄=3X|.:~ ;,]]?^=7:t'nC(<\-/i4h9u~pa|0Ox\|\t-ANH0BYۜD;xf*[s0D⥐$P?U^;*00śz0,OEz &S/x,z܋*^n'aȉۺxSտ-,>M-lw?fU3Z[rx;l(zHVHXޯe#Bs&{%gˣOݳ endstream endobj 588 0 obj << /Length 725 /Filter /FlateDecode >> stream xVMs0Wp L;|v:b$+NCDzڷowJ;N@frL#$ P,N!aA"8̹skuz` M !}D3|hQTy>"D)YYq}:'&3G,hw H!m=PpT䅨!D;c>c.! &:?L'A6ԆAt Iip 2~6C ?Y\531t?-aLh~!9}o&Ν` ;^-&w endstream endobj 404 0 obj << /Type /ObjStm /N 100 /First 882 /Length 1897 /Filter /FlateDecode >> stream xڵY]o8}c ? tfw<(c[%g{2vjls)#4/>I阑I.reZIԸL@וf6Q9g3/z`>⺖,X-aX&h hHR30 20)ϖU ,qٓQd9h3* G*A̽DR.x-FcJhD4`Jc )#Ly4x4f-ي@xɹD>Z2p<C*+5 Tpg>7haƢ%ݤ8NW- ^Nkdh= gi 4y5QO[K(X(K@vd jO= ug `Fh@A5(`BA5E Q.2(,.AAY 6Cc"# GY}H a,Id=A8g ogNzjZ>)GwY4mt[q bC;P9t[鼊C]eŲ͔_wE=޻/;|!9wTm-! T oYNi7e5ü8ͷndrIE~b@8_kR4j0{2JC.%f٘.MuM9MwJm kb.òy]' Sq5~8NNR' UVgl-\;) ׆Y<{AvxM\eBrM&f>>ŋmOQpmzWG~5a[ր ?38IѢs*\n^b0{/OOdKhft3A/˜]"n%ZV5-FvtXsѓg}];g٧"^v0+XjӦf;΋ZE]gŰY_I|TW=@q/ =;N~{Df:>^,kղڴUor~brWٿ?$W~а;r-$s:3s%,],`f𰵐 x%>ݨif?lXfRp)tȦ 2Epml[iі+(]SJ>b^(Er:Ќ逛hޒkljWsOHӞj-K[:VI. >a"r:!` A*y8r,f`P)ntU*˵SL["Uc2 :w\vN]o1/mٌ׼ͷB]L(KgmcyTp\jzKj|t-=OB"Rʺ^>9(\oUyVϚ?,=|Xܭ[]2&1m4NJ$?ad~w#A,XGo:( ~W..|E9]WmE]Z6 /߄!HzK1\K(Q ̌ ]Yqz/Wsu7U:ZՄ^goj+ʊ?o endstream endobj 644 0 obj << /Length 946 /Filter /FlateDecode >> stream xM:+lGFi 1m iE̿NӔ2|MAbΦi%yII Hpsu=dU`! 8 eڇJ#KɯJۦztNj5)u.7δ/s/3 8 F7PzYm}(u2I"9(?LLtY䅽֜GgOD՟\x0Vir?y ff0!m^"Ke9Skb53LrF(ɹ\7q3$DSڝaxdԔeg*Asّ{y>>+4h>~;PxN㝀+cWuqA%,>L;NQL Bߛc:GIQޣ( L鋒4 F*{at;VZ!7 q_sL] E%Lɜ> 2yӕ 1!jg[f-b _ɲkb׶?qtkL: e `QoZK̇ޖæM&>$ұ [y>$gI*.W޹HyQ^>F1eOA΁pqYBA5f' ><G{=zlֹ,&- :?+`W>F? ,Rp FxsV endstream endobj 736 0 obj << /Length 1028 /Filter /FlateDecode >> stream xMoF<2.Pq` A"7k~*M}wMV I{\Dɠ)yG { /_gwz20oK8)xDJoVx42|w։)S%#& ]y$׵n.~q67g dQB}pӲ7ɵHaxxJiۀcGt}T8w8ڇ0!QE׮*$>jj"k ,>(fac=0_!y@k/OQ0eetw3SƆi;dC&9S`--Sd>^֡fV FKptgߜQUYB!LB!8~{f~k}Ҷ5ʸM9?c,@Sxq=zO6@n.RnuhS")Ӿ[IM {JJect<טwF /iU]DV++WqT"BHuqUwc.U~g:<_4 1>CTI2C;c8˶lJ DrPkΕ2$6 >֙ U+5Α;{Yj> H*0G]j3'"rEIk@N3 BdS1^wʜu’f)[ïu$_}+Ą!̾ AE=ݍiYbyzwc3![טe oAӴw#?ߍS->cAuEy v]. #2J^%ϭ= q8o\mDy&qt"AEN߫>Y>)uXyתra,Ao+U H'nͯml =r=Jpr~xє`J4E[)I^'x6 W_ endstream endobj 646 0 obj << /Type /ObjStm /N 100 /First 921 /Length 2041 /Filter /FlateDecode >> stream xŚM+_z> H!-/#Ʈ!.%@\M@&b9LңTbh{.hD(Z/Ԩc# ΍Q݋VHJk\\pD EBCf^lgX"sVG9Q+DLRIp{يtFd"g(1;"[Ѧ~JȘ KQh0slECWkNte9AŔ9ALp9aݍ s2gqLlN{3njŔfk+f&\P?"VQ|sc:#ۼc^1\#Vܠ$1i1ȐN3="82aŽH;rX@+aǹ:8ܐ([xCq n Ɛ:Ixxp|_: 7Y~8~͇!;~ۛ˛qo"77kطl=vߵ-g+j=[ֳl3euc(} etc}'V<9e9X=@hsX]ܘƺ_ލp뱋E><ōE><`8׍_ލY\knlݘ.nqc~ۃSwݘ˻1oXD=`8׍9]ލ9_ލ\ލ^ލyō؍u[~y7qy7n,n,n,n,nlsX.nLn,n,vP4X#n,v0 +e6> stream xMO09H$8ԖPfJI|mR:CS y^l#g xpz#GE:!B&a0,qLܡsE{ed3*YRz~DzJniXqLf_1D#zy}Yz Ax>EG R>@@8+ס:FdOБ8`<7և D{ /+BNhJuW,Q <vT5 )ly{r0j֫˯eiE]S*+~ǥ΄5"=Wլ0. -Ugb(e/o#[ `흀wN\6L^YU:!@?=gV"m_coV'`6uO.U"pܗתteej DDt7]\|0/T5!g0-Ą[9>] 2}8RHl}& IHZZ50|W2iʝV́dʪdi{>wOڱ/7zЄI[& uڂl>T:1]/e0[6[LDn"T&?ƞ@nQZcu{Ֆ2z/haGl$[P΋+1p.G*~tU hMd1˒Y}̋GK`u`TQ #ҖcK1:!O"$뜁mR Rﭚ:S ݃ó6Vpkܒ6y#D~kpGrz}iG; `'_//r!D[olNQ #P6 vW/# exRJѬ?_㞞k>恠#p~H}=%d +i<= endstream endobj 880 0 obj << /Length 1682 /Filter /FlateDecode >> stream xY[o6~У 4)QCӦe ÖhK$f$H/Ǹ;w:Y:0zs1gy̹X8cS愄 E\ll>=!5Zd.ENnyr×Ba{Ի#!SX&I7́Wqkҡ$><|ZB6aApL٦9&Rq4`w]҂1k Yۗy,y~+< B(CQr001Lyչ]P8wS}9S)E{89ʘ;Hvipϴ&CCE4",wJ)kTRdzLT3gaCV؛ 6_y^)&A#Dhꖶ;~љvQ.TZ2 v6`FשՃnzKϱG~t? *H0Sg̋FQp|0")i7 Y`( ,W&m{Ɏ:m>hXiml}#o df! ^suɍ>}ņU#ŷ|ы}&X_wh3~st2l7kh:-5{W ۬Bd rM0#cYndbq&nem;d~Fp!&5͛M/Zs endstream endobj 897 0 obj << /Length 1258 /Filter /FlateDecode >> stream xWo6_!&1K)=G"˰KFb Ir;~HlMEHw4Vf.g %(!Q=A4w壷UQBU.նje\/?~χH䛻B̰{r=ҿE(%^]]c/%Ű=F.ٟݯ1A#ΈǣEQzi Qo We0#/zViͫȝRp덕8‰UM5iowqY` j1Aui"(b iNtzudz]2(H.PDwGt< (feȕqqU00/U{We"-$ct(lyDc H3@;@O8Vl[UvZC3xQZmso`|( Y<=cz\Q-sQ Gcu>.U H e6~SCAN`N?eʮJ_ Ilu24фF^+HB_[uL Z޹g7e 4N ,'XEdD 5@tvO-:ƈ.J$~Q,Bi^j2Vo<=JInpwC+ x:}FyFfݽjupt 9xt`8ʫqlP7ӵQ( (|eV|D[6Us7U@L˰Ei4r\_ΕEڒu$T 0a _f L^f2m̲\K^GN†-P"$(k`77J~uk1g;9 COn耴J$,9ʬLmf́ivM{I#,`$> }N\#Tu-Կqåf{6B;[gp'oL&L](xwqy6` \H2A `v%,HA#Qgm*s#{:Aƻv?iM;7VqkUo.|4]?_4t3G5m> stream x͚Qo S$%H{8$)ȃco7ŵj8'>qs4;~#)+QSG3T+eq*V(# QCQ,(ʎR{e{I!Uq☬U1T\Tbjp X*9ĢTvBH\${&Y".Yeu1U.b r,4hN"%\XUNNZ!':jCSL%NSTH&v)1**k*'*[rH ʸEEVΒuM2T|28`PƗ*PW%*g Ce<ʍllcBnӌ7=/xBER1]R pg"AGpZ5Y$hL_BD;/2 ER( dj2W NjOu=^6dC:]Jٮ$FBCkAA jw8@Oڃ+I s\AzEGSBopv,%c6q!\+ sfgMHӧ;*+7DO('_\]cr}q>uKsB϶^0<'xkr}zu닗nx_-@Kbxڬ/OV_Wg?sG^&_~f/3j]\!yc1-K/u[j%{߇l.O<Rz_Sٖ]^jW.n3ٖKe22R{QG]uyQG]uy^ ]߿]{1<]] o ?Ϗ=V@-fe/\ T{~v>C[|OLʐ+1p )CN)=:\BVJ}De`[RI0zluOBG:?+`9,&4j6XLȾ@S̞m-!;S0 pV[[νaA;1My81Q*+,! x'H?j`1R}F~ Tx~?/Kq5=0M\Ԗl RQDN{!8iYEt/)9aҒqGz$%\a٣;-RÇ3q #m`΂<iN1Tc1vR'`z?5.SHylKTQԶ˘.}Z jvQ26Va3gE> stream xW[o0~ϯ@=tLI[ҽdQEf"v~ T8>wNs`tpr3'@O}gtƈq 4rfC9O?\:!)81I3dezKkl.s>*<=Txz.mµ2wr5#њAK }tdH&wD{VhfuR֣A8)|cHqȊ`iwRq BqDӆ> q I+<ݮ!ϖZ 2VQd‡2K=׌et@)FÈxCE~Чi[}\wR]Ĝa؉*{/ubS,V,7_%Ork=y~ q!x:Pvݴg1Q!͡CUe O>Vuް[@WvK$EEr^*#35b:6}t[횸Ѧ7uX7D1 ,D-mEw74B)UO=j(2[8Tꀈ&{k] w)\dl] 42CnqJ Z<$}\B t4t/ԶTh6KtkcT#1h&z0c'GЂX ǂtp&kcg2z‹=ٜ` y?LS,h}P[=i|XU1,"͊C;V &>W"]tcWsMjͼb܄kYDBV=#k=oEٝaAg{}Mh=ߩVB10ev![swZyWorJ]^5 hɂX1ZWD{]NX4 endstream endobj 942 0 obj << /Length 1010 /Filter /FlateDecode >> stream xWKHW [ZzIYa6)팳$nc" ^-1&(ꮪ*{{=s>SH4+`xыjpۃ>a GV&K]^nF_^lܬ8BiyUnݼFe~( =I)$eZ&[3Hęh[inX(QQEnzFmm[:Y%Y<:ZWјS,Z~ٕ1!44 SؑKtc]eiXCD95 ):ҝ> 2*Di <H G)DvG`B) xΛ;@GUgGIT ur)KW#]@wJo|%a*эǡH`zwNV禗 O2.[I)st!W:8ܑHq6,ۓ(T'x"*,2uQb[_\ JKpS]T=P./ *=Qm8/Fd3}d=*}mH/S UaRdG(呄P eSŵ1o38Twn)Cj}H1n+RYvl68cqEnȞ-\!^RnU˻Na* rYhPo?:Do.~‡C7p*bP&`rM0sAj@Տ0ij#odf5uٶhoΨ0d*Uk*2l>A]YIe)sxh7$!NیN;zRk;_\`HI?\ endstream endobj 969 0 obj << /Length 1084 /Filter /FlateDecode >> stream xڽWo6~_Af6C%$E.bw/^P(OlN"eK:^Pxw;ia9: 9@D dQsG1%VSQ3JN8 /&si_ <̰Lzvu$ɡsdam46WLf&!c/MY&,J" Kg`pF vL}gQ*fjRyuOb$K{P2UBQ/<,imL <$n,sQjvBRA&δczAɐD/\mP42w8Q0(v ZB軅Nu")?#SNWNEFsƦR^0Mzɶ;Jr\SB-G! 0-,` co4,tY<LPθ*)Mk[Rě5WAM{c˴9f4[Pr/+1[zq /(rur(9[Xf|% NFPPT*(muzauU>2uFVc[C_Vg7iR |{3?{74zH^za endstream endobj 988 0 obj << /Length 1026 /Filter /FlateDecode >> stream xڵW[o6~ Ї@ŒE^-Vd-ڸ} ˌA2Iɼ#يDEs\M~b] `-n%\R, q]{|]lŇ'G 6Gfĩy=$vDI加 |s4Gx >wC`)-_ ]΃Kg!9%6MnʮUi8DŽ=T  9*):-v#=֑D>UXу5@!hKԙ*lՒ«9*9z?][Y欃?,QEZGxܙ$+'3uu۲a*vF6H* -ʝhlPډ91Ed~⭞ȱ|/~Hwgbc׷Eicd09._##}|Ü hRSr|]IBe+=ūCwuuﰸ?(pZpW'"@B='`8T{@ i)sPLq9hvd}Ϫ%NNRS̋I bdʜ~]ʪBxzeAIc!n߹=s:պS՛#QY1?JOCm:_#Kl>ӏ:3hŠH -<3CD9U["!A<斆Q"9P[z$HmNH Q& oƤL kKUkiU%0⸗'8}]-Մ>+c#I=Ӛ !z,drC> stream xKo@+-;c($p)=恒83Ǝ:7r4of)AKDНf&#dHQ%7h6G>ehڞ\EXy*8S{tȱdg / K ;MhVC"4>rfHD^aD1?iYcCq.S[[ҹidnG^9 6qj /. XD b/q@ lbΐW.SAQ z]w.RL] 3oK>Xώe8'5 E%Sa.]q|i0*v޽VZlL7_PoRw50̏7n'+aEjRH4s}lenhU6Z"Rd?4w~U[$``otv +"%BQд#Y{9oSW~b͋ZcyS^T#D+09f%U~k$[5sTV]VG_ߤ>DXl0_7 ?-Bp `ہh0iin ?S endstream endobj 1021 0 obj << /Length 1010 /Filter /FlateDecode >> stream xVKo6C%bHD=nS H@k*FzR$[^w#j^#q p `ƈ2d NE\7HeUy>6`,oVPŗdp30A[| ~ ȃU g\׋_W?c Fq@8gH8Iq5nw312v6'3=࠙3OJmʦf1(+ûj=?T)`_3+j*N qֱ D`F8iɃ})!qB ^+rMݺSݶY9yݴN(*= 0f|T&d'Ѻ;5 zWL@ $9h[>||DI^"eז3`8;o2 nb$_DtK,:wSt֦4+Nhh>D{AӐ $ܕZYzKZvIP"֍eUPݙm<~G"κ]>wޮ}^ <IH<ӗVRxI9HZ˯@8Ys'^ >f> stream xYKoIWqE"v7`:6 _'Mxưzh .8:MɥP(Qő&2X\J8g cNbc爍mb}\L)e@``3"c7LuQCFG.:ɥ3: (*@y] N1HEGm't*fJtf )`1xVP8:Ŋ19"eAY f{I:r4P 2+)dqĜR䔡#2I.A0ءƈeJP*I!+ך]a_;DTHe݁* Zm&9\3t (sS qL|0 !`YL83~zb`fU }I(0u8,z5z$``j1;!j#i$/A H OB!bpD e bOK0x`0|NLZvÿdvY {y:};xvpH>mC法{ `*h:z1 DprV/~)3X|b~z<^7]}|4 8g%.7ryq:^6z9>ϿۏMb46$`Rp =횴҂9yl%U|;ԛG;h`xBpqvnY_F|e5✮qw2lNpg\,ڭܶmmmkj~GYw0>9qӓfW0,> )s%5?vg7s? 3g)s-%d HHv1-0My%=܋1 z's&Yr)S^:H䬸Uy'j1ڧL2|ɳ{hL" ogѧ=$&a4k|n}E#nNigG:-n9GMedU\aK>KǕKDd|0_b%ȵ# OYQxA -S'[ywCz-f7ft붍nnc7s1D1 ,`V;S-*}^VOYX:6萙4[̧P֌eUbR:z:NGWPP#8H H2]{'G;8 Y}GQl-:ԸyRC Kd{q6{M rzp u'x@j@'lRQ;jDž#R5ϋ'^'Od]i{mۺͽր&4He3ʎ5ѧ~ sEZj6a@ A]7ZT(D(J=֎L>?N"sϨ^U`)["Kha@7_Ýs?oÐH"+TU/`a |{wjID,ފ;|Wp]rGt& h+ v##+ѩ/Z9l~JG1\|2Q;y֟~AfКqYaH iS!V endstream endobj 1049 0 obj << /Length 1249 /Filter /FlateDecode >> stream xڽXmo6_&#eˀb]eYAˌE\QNERDZQGޝCoϓfz)J#y+!,bQDSo.|̦'gq%% =S]p3%Eț;-3 %0CzH 8/F ϓ3h/)"QbdնiGJbCYV~i@x/D#Hm ebߚkWy~{7=@4:+57T*ʞ PX-U($z g(Nre^ê!tΗyRn@6+ѸQ|vSsՕ+šTYM]in?Y2oFJf L# Q8>N1ƾSۤU>ϛ\UQnNngY])+@,qn vv-qo)ⱾGi $s~NR]j ӫ@0f(ەÜ0[I!6%KiulT7t Ifh5 ?H(fq^5mbpnWB}gJZc1? bC8x 3؛5݄K}e>;~-Gx21 ͧ0ŋG9~3(?gݖ-іU ,\6C̅}Gn}Rզțg;)FrΕ<q51xzrqz 4nەk,6:mg6LZ8#Ap%@SGj}jȾ>'g8iLͤQKUo|fcU/5~t]hS1TB#3NU&a%̢#_!Jݿ]W|20Jr)!)HI X+?t^} )7#P /VpdW[;B}M dk fctԶ6S2E1ڛwQxC$s ߀_F endstream endobj 1095 0 obj << /Length 2232 /Filter /FlateDecode >> stream xڽYݏ6"( lrبe0phwp7;PķZN,2MR)E߯.1eq/n<E9E.ƨGKe_ΒZb."p"6Ю:L`N'^rWPpbڢF¦C$fNZ[$ô<$ģ[]U'n&EG0P8Onu #D,;Z\/1)ddTG5J",1dFɒ;,M=  Xh𑆿bȌ?ΐh7v.H^< h3amY w~M[#qQ(^zkdew ,-#]a)eKZ/<;+ OOF, `+rc痛E,^i8Bc&g/>?nK~ӧ+'K}NV.]9E^PNn(cyI6'R`G>e']TbE56٫ן.+f֒=:鴿x{u|q},x2K_D`$*.~9"]!,8pdX$IFn11NخrDd6:o-_`kF:f",J\m89o[0*}<*gKMY}HշHE5Q2d Ƅ^z16aqU8=_Rs倀[jX,1oiXX7(V+LIr͵F<[jؾDDfWKqW>` [a%’ ƦsrPSLF `ѳKnW+)f[ 3g. &nd F'O٤Xgg.>N\zHɢ,K&e~":+4XUWfڏd endstream endobj 1119 0 obj << /Length 1390 /Filter /FlateDecode >> stream xXIoFW RNf2A)H jM-F Ȳ^p8{ew'J(TF1.#E,ɔoU$ :ndmfNgiN.T&sWT뢩{dB&@#"GJ} nYyӫӬXΗLʹ;,[]gyJ7/0%QmdqߌHDX";kxX+'@W3{`$GWV0,ɯ_BܯA Hr1m-ڣ (5OQtUWUX~B}RZ {h:DS7V4 n| -"ǡaU *FS]P8K\@)ܽwDuU:`g%|m1?^Li4"[xk 'CL7f͈x6M-1DZep"3>SV,j]5ZjzٚnmJbJQ[3i v)HLU8d-iBz$[BXvT/]17_rO P# E9:f:.j\UvGb 77qFđy8x=# z?Y@lF B2k})nr+lp_JJi x{˭h=Ř!䷒d+tk c +oE\YwDxuYv&Kgܸ(gɮq_^ǿ'ӳ>=(! cU)Rh&g&(twK)f(eh Ź|so0@('M1@ItkʋivYyPniRD12&wkrzCs+}: ;a#:)1PDz.C uXe߬6͋MiC_z!%ڼ(Sjq V{y;)?y&sPzSx,Kє"0*k~w5ռ 'XWm Py~4ޖ&0<+4 LnZ0_*Unsy[n˚"u[_ǀ` @ endstream endobj 1035 0 obj << /Type /ObjStm /N 100 /First 968 /Length 2046 /Filter /FlateDecode >> stream xZK7ϯ1P_6}#{g3f|EFk|aEcMGd*5;b1: s409')=;%9 N5bPZ\b$"֝dW@;g2u@`}*nV*1 j2PPa" եOUH q,5 Qlj*)5}t'A?.( oUkQIfBVk)M"jfr .5ZZ$,M`|r}PeK6U ( a (EiӨEm@1NT5{ZT;,Ƃ)&a!ᷔ1֮by(E]b)YL.i'mΑ۴J5 d,/&Qe2wYS`e;lrM*.T]i.dQւD@&+3AJ2[+܊`R 1a=0 fP٬]`C1Cu',j0*Mz {@Bohw5,kJ-24 ՚MWKi-<8=vXp~f?XpHq?|CmSYi#<#is>c9GjS$pJcG){dyq .ٓo`{ LKOva~Y-_?_lܹXqq_|x0,7kKڟ͞-˛zo?/..?.p6bB/1|Vtzη𴊱JNwA]]Ʉg76gŪ/gsڍ5l$XvE@p&ԡ5\ z*=w/ݳ7?X^yp> x  GP|_fBP5tPaDVfѰt3P,q pK-䣈Χ^/P@73dr$[dLgɡWP$(0zcGnx-VoSQ_FgC`.7.{m%@J#y^lw˻ޚ|)$t<ɴtyziXZ\k+Š>Vp*OX9ˌۼ"*N2 (~Bձ6aɾ7U\ 1sVbR9!y:ƱI9L*u;]ʝ.NrKӥRD,w";˽{.{.2%%Վ 1/ i_nlb _G0Cj^OX8{wHgH}@5ʞE ׁt7dodu(rRt7礼o)y_䵖= ]( <7{Jv\K1`.<?! xKdd;;Ge> ( y;*>3|śb5QO%`mq,L\7߂7+gCaZ~v#;/[j2N[hՑ':&pr_~"yqzm S> stream xWMo0W ƛv%TФ=xछHP?aT`~??їh:#A66kA!j,Cc5e|\~p_D+,&# [bkic&bQ.)׹q:s*T؞ 4`A85$X[tE'z F4352Lב\徺R G[=šDM^W!#2q 3-ۃ~u<1%Y݋桚g=IT}:nٖk5L荔 p6nY7QjY&wiZtPucˣ#q=~>@h=&9.ȫf@xySM8Z7ˣآ5V|#n>2VM*Ȯ *w>!d\8YIS%e7 7Sc endstream endobj 1160 0 obj << /Length 1008 /Filter /FlateDecode >> stream xW[oF~WXPa2_Cl"U(E+ 4̌m<&aW+UQ}nߙceV|m]#,+k1$h9kj2!Gm7 &uńzpi/mX: s AW <*:0W'ф:xXlBW2% ^M @\d5k%G炯jف LpTn-ܮ:&ƒjZ(AγTKoCɩQ-oˌ:6":D\j*eFD&XHd +ؓYp7je7G &ϛ7`l-бpUwz|Z.q8B!n_@_e˶/BBl & 4kV.c7#r9}ai !ODHP4׎Tgs(@rh]IyEdMT? u*ޠr|πD=o=XQ:X,^jj0=XIsA!\p O3f~=!?y^nfH|MHy>aWNNԇ ސidžLa5\Dy+v5[ NcQm%f/4ϭDSޮv~6NjX4}6?7OY~v [2Wi6/"|_zy[9/1y<5Ifڇ/ bV{h/0].tsR!h!X endstream endobj 1177 0 obj << /Length 1148 /Filter /FlateDecode >> stream xڽW[o6~ЇJ̐E-I"hK DZdv;H%K0`0b^|;08 p~rvt*@")`bA Ep,_N>YR" {G46s*.v,oDpuuSi&2D^[G2RʐLڵY7!JsrI7sL{'KO\]5Bm[g* -O2'X:gKF;= z`DRS'YzQN><)|Pm/i$~BvHm2ΜMgxkmT4 [fmjȜv}׸Uݮ 3Ȣ#H0vj V(IA JOxOTi1 r~>!( J vk65DO YU~6{A!P"VpJN1*Q`cʘVWinGPS,6f[~q6$_W7a>eч6PS;LΌq2J6ΟLM9n_zz,,ixfC̟?PY1Mu?&+L&jdyR}^MxhbUU 3{Hg}By:3SUYMG0CB|cd AKf @KueD ;U;G HTuTە`z?>|`?ĩLQoC,~<<8q1] endstream endobj 1191 0 obj << /Length 750 /Filter /FlateDecode >> stream xV[o0~ϯZxĉKh2I6!;DZ5!][@H{ܾsl戠Klb<8&3D {N&Stgdp7y:ےaSɜe2 ̕Eg[JFf>:Z1\t9AP>i9q5v Ro^2;&âHemJp3}d40 ՟~TiA:+XIoauA{Mh{.׹BOo,,,Ȩ^ɼ+Tgw|>'jQH Af:0u{G!o |]!܁}2VԃJnQ8EbFZ Pe8醋l0.Lzs]is:?_ɤU}זD0Ha$B5{|.([+wڡݯ@FЩ'v*[.1Dùy8wH0PaJE7{F~ZmƒTMC3;E ,\c"<AVfPPin"5 fA~[X0& 7qbfDཡ~\F93U],/^M endstream endobj 1206 0 obj << /Length 963 /Filter /FlateDecode >> stream xڥVK6Wȡ1|JbM)uzIrʲV\I_d3^osE 7$hyv1{.Ha-VHPJ)NB%81˟ϋo%cA(N3f$"3,N8f)qW<DhA{Zb29y[]53*kF1dؔQ$-he߼+#*mjvvx߷e7z1qq 2FswYZ"$Nyb0|O*?Խ ,T]jT*Qm(jTAg'?|nYLf):GeN M3 sKS;|ih3w2 R/a;-a endstream endobj 1219 0 obj << /Length 942 /Filter /FlateDecode >> stream xWo0~篰Ը'q=LJ+t/R04S1%gB !N|Ȅ0a:>QT"$1Q?I9 }E#-D%})|Yf -KFx6*"iwFFyM`Kw):%X>W% c猆'}GTżN l^'meǏ?&Sze,<(C4#U2F "O3ֆИx\Ql,? 䏖pdkg%r9=19^aV6 &Fݠn/It$cmJ)B7O(CQd9|t>SR5jx0K.vNT%[q3kL, E8~IE ̒gm1͍4tggpwJ$ke:ӣհAeOIBVQ"VN[gjgyO[]iQ.խةxC*v'~qů4@jۊjK9@KxvgCU_im4 2DqWCm7JPX:n(IWN ]3uŪ8CK f&yLtdWWUho:ּ/U G-;t+|LIgpچy{+"\uoW P!XTw1X0z,|F'GZ)`nk]&[3>ݮ *@'+×ڕ3L 6u9[;U:9n (:{6ٴnf{*,hL^(0fƨvj=N?h.4<\'Kb|_dfZh endstream endobj 1235 0 obj << /Length 916 /Filter /FlateDecode >> stream xڵVYO@~ϯG["fB}U}2&q6+I IK_=fh0:LFgC4D9"{QDMf\\xdMƅ{7<< }L(eRdٱ֘>r;-r{upx(á]$:Op_L"s#d8"# >]5-Fw`Vg%Z |] :_;>A!`7E=Kbb>;vDʴj]?pgږMTa@8w/+]AQ/\LɪrkH `[ǽPi-݈tw4isY<=~22͚7m]ze+舜_]Zj.q-o<*ъtT녠(&Sck֩V=ccLB/HL½,ǡ{U-Sz30ӜQÜ40r5ˊÚ6orawDce1þ3s z bFV9"v ÅKu [sig 5MY84~xP}s~^jñzPǖ\2BΘɓp˻":NڍfYW2;kw~Q(+M(0{US 4%Wp-Bz$+W2Q$Ó~%ВE5Yt\h0C*_amR>^>oA)pU*_]zUJL54ʊ1 /D5F1 fivJz-.И|%w b/d}h?_W7ڝ07vHҫ+,a,U^ɉ]o& 7"PӖF </K2 endstream endobj 1142 0 obj << /Type /ObjStm /N 100 /First 968 /Length 1580 /Filter /FlateDecode >> stream xYMo7W^(rr##i(9(&6H,ɿ2Ȏi[Z kvq8 # .X\4lP1Tu9V9,$'du%rF{.j ))C/S1UJ+>=&h=Fc lԤM#(IPf|JQEj:؈wmD&`)P+`&@I  & ٤ږ[q &HJrd3A8 8S2B]RJ.s[m*8m* )(Ԗ|-A6K^,d53)@sFإ4S!aMx@#/( 0b-)@ l}SQcH1($-A[ͤw}g5I\&Zj)c^-ʩTo4lqFLJ 3{Kl#} h#*$OV#YY-8 Fjb 9ˡ-jSa?%% |Tm*̆MMX.C7wQN^~vYCMnoύ_"#mK!Vg{+XAx_?Ta9g'G/e}h6 Ņep1 ˬ6OϾcEMep:A2}=LE{~}>g4~><2u8+eIo h7_ٛ^t~ˏן9WִB\oj۩BɃN;^h ,pyF⹅34Y'w8HئII^ԕVB^ N9U'$&ģXvVN|dP3&P|B|KFݦřߝIV_%=[]:2 їjV=3 _!!|ߌO-jܵ% ȝO> eo5kes֕ewVDO$(ci?="L"%zk;єQ6Fب(kǃH)E"k*"eU;Je@ *bsp9,v Q$m؎) <[b199 "uuNhb/:,K T܋nL{(Q:~n RҀP~)`uݽMhf`~8i9K/: Z܉8.|3<3]<4쎩;6wՍ蜒/QډN&W5sl>th5v{ kE&],n쎱5svx%.:Lo7P]T4yXq侵:=4|.ۼ.`+{ع;Ϟ]/AO+sXB}oE$7]JA> @It*QIK' J-@b/MTyȑ& *U팭uUFtDf=<¾v)bԉNaID$/؈X)ަ߰fǿ6 endstream endobj 1260 0 obj << /Length 1146 /Filter /FlateDecode >> stream xڽWKo6W"%jmRص4Ebl-dգi})8N6X04ypo(<6_E$(d0wS6Yq~OONv_d5uAVmfغt a34.9߀!W}W_16 Y!m}Mfn%/dߤ<uV9 1bqdLt%]~B|T7ڐYVfUY/M5BDmQJi>ī~xdY ױSou+scPQ2Z37F4% *1܄"SnI%"(Ce/nхaz)NL)*f-^n<^El$0+WݙEW|aW2teY~Wsl[l:3?l!O-LwN !e+Ӑrό&H1 $be r'Ga"{}t1>KcOKK mcGBAMki0v@ hrj(xr~81 Ex<8WfM튺zMOҪ^m<:~n]0k.o[īϰT AZ귓|IxCt q> stream xW]o0}ϯԇԸPl p6WqU`W3RB) G]661-(C}q>;B;Z긔 8mET :.nI|c0{XAA)(s`$s3zB&z{*s_i]IfJ\Vk4WEǺgk`D1Tdl' od ?JÕJT.7d*y9do̚b.> stream xڽXr8+XUA YeIWRH;IςزMv}A ‚H>±֖c}s~q}+B}k\AuO"k^.?w}IEf-"O޲r/y}‘@ a7u.DLJ \jfc\٢( # >!O#uC2=U^nilW#B {a%s2n*7Kst\RM*MOu3bb2q^Q":N)=-c1s%*W7c3L/;SLҧWqv.usU%Wd~Ni4yCH_]ȌJh`*%??>]z?%&VJˁXd ȥ$ߕ"}(Fy" <*gVIjpt/'WW-cEОp}\gwqǡLUO2Lp0<y8Sѓ6%+Vxz(n -١V)Cx ;P/5V\#)3Z,*ɒ{ jd,g+Jý1YK8cm}c+3.XTiHu859u<;Il]n>{Y}e6Ɠ>+=As|xMJ vX&k, liv̲E֍Emʻqk*kPyZgk'ŔU蓦fe"Yx@]:o6K3ox&}N.5>*Rn0rWiQ͐fiW9E$F*rU@}2ui' e>r!`#_(17q0 6oSRugoyT|E`A%&~Ug5qUs6p3|x+}"ަI@-_$M}"8Xm~=F}NÏն]`c^θ> stream xڽV[o0}ϯR`lS`O(`Cs0Ks{1DaB6!]zۉ5xL sɢ}wURߚ7.ls0 XUYY$&nH9R*\gR*-rWEN݊B1wZ'Cc2o{B>L~E5cH M9wzʐCJ3rN aHZ y $*lkW0jt~@<7 ]dpxcq;aAvS*[T٭iR"}!TO !Y!3(@$@yk.㩨˨rS JFs1VxxP6ӯ˭Xc,lSV C8izsYK;z2Kw5ӳ JRTJw'%Ox 핧!4<إU4{9TK+i~]W/ՖW/d/ !([gV^wc֬_EUɞ!)Vע'6E<$F^[:wWNۛS17&Z,6tm0=QҜ"ijHw|o9z' endstream endobj 1327 0 obj << /Length 932 /Filter /FlateDecode >> stream xڵVKO@Wġ뵪($ &* ;vDAP|3<4C:| C1h4E$0E`b4!,jK2ccdNr(?j\;t:<pHBLGtp{ ^ 8%kDS3X/{okpFB,8A"04YN:sX6U4 ת=))x%fCA7B[sbyXS"H,^V-|941F}ȕG<ŋ+w8;[ޫ̐[t*a֪"p1^"+A0O2{J\3MUyMdER.d*QCVc!osɹHv|Mp]Osusy鎟E\5lǐpVjY;÷-l*bǑ?A6u.D@q -)6C j⨟9S r*^mxcmaU˦k0m$ ΀qmQ gulX}E.?B.wQʨ/KCaY5']m迺BlHkO/Þ{^IԞ5sXyykkOc\WM55R'ǢVqShFklU^wjTrLlxa?z)t-8]y.WL:ͳVak6*WvOq扢0S#?|N%uW(2ÉգU5V=:f*jGG g+2ϮŢا}*x;1[_b]Ye:M=-;Id?ty[<*rvq7*ψޒEC);Ozak endstream endobj 1341 0 obj << /Length 1234 /Filter /FlateDecode >> stream xWK6W(k.$=l"ݤ=9(m+K[w;Ç,6Z(| 9g8o>SkmQٷm[ IǬr)%~u k[훆/6}~w [6PD1X;UfT@w^2_mY4KuhG  ܘX#IW -vx|= p-*-JMES<1rjCO"=ݱwb8P6-?yDE+xYq[or^AYtp1js!.*%MKz*6޲M+gڻ,>\(bOIFL6 Cl n;0L@9CE%:2@Z+:?A}JPqǃԢVCZH&o2DB:¼wAbTtፖdhB%KY,X rέŬrUntTiue*jS|{E]◾,B$m["Vc K{bSFr'cL+-;>қGb=j1 Q5}皽^$xAHmg?Q+(Obk'UV>K짯6(VǮ(!aR[E# ܼki?NZ YDxe\zm;fM!q1֧ʧ EbQjVP )'k 58H\xQ_l6=2lL ;1jrnuOd&So/jt_dJ1:ě$BRj*Z#f[_9,WȒqD :o U!  RBlz?ߓ]Ǩ4=;s^hLKM2)7@Q͡ekSS_Ğ/f'8$1pDj1mڗ0f endstream endobj 1246 0 obj << /Type /ObjStm /N 100 /First 971 /Length 1785 /Filter /FlateDecode >> stream xZKo7W^(! hH[ 8v8R E %9e+[JR kv<8/(ov5:'Ҝ(NDuœc \6` sr b1!?\^)c" TA1 ٤0Ku-_@PPRxZMYjjv8@@;L؂7Ž#[QLw97Tno(fRިQFnCMt؟^4+hk()$W !ShTPL1D8VW@i6™bPErӣ (s 2͹]6 |%P)2j`B]Q j|qRW6b@$()%$BKJ$)O#(N0W~CF`D,XTT%4HK)bR[^XT.jMܣdjO)׆+Ns`ѩ6C$eXF N &l%PVEiMq`#xbx7x !Ç_FS >#{S~6yv3r.6_eq~?ýOù\ 3`M.l ڽ7Zk,4mعh<<<-. rX$%D^҈kzý7`x2=Mz}j!LC>tZiqJcQsǞ:y5qpO/ÓttxM.'o&B NNޞot>=OF;?G:+_5ⷮU?|zp'={.VŻnzzW}@Œ4 FBJ"t^ a ghvu'[1H)ңiR~;P=Y][ Vm[{19/κ`g6Ū[?+}6kJE|`!XV}muddֱeoJcOs+{h-S[Pk? [=U𲇐0Dg쁂')VvfUo]rOtvMfuu=gm N{0=j,ּ҃ej$ #H'& E˔oO+qe8 k4rc(&:HQ1o>+KM2֬lLIKe1խ| A)G4hKBNuu<%5Y KJO\Ik%ujNom$nDg{YYxk5;xu}F]mц-Zq5xޛD_TCFDK.-w̋LQ;CMNr[I&KLK[DVK$XX۟-tƌ~Ͼ,&WȄ#FC$E_pX"*Dz&De7hoIJ[E)Io}%ac zDSA1WN9jɋ%> m^ Q&Jgfl6W7{|u0dݠ1$.}ѱ~\AOt )Ѝ.hFɰm@c&kv7:Ĕh58=8yяmF)ʭMLć}CQP~i(gw}.EYq}_2t:6A¸ ߄Ψ%IOt~ :sϵh6-k[ endstream endobj 1365 0 obj << /Length 1194 /Filter /FlateDecode >> stream xXYo6~*WE=mv>H}I-ѶvuxE*ǿl%#'- ř0v|ۈ8)J r+>"a"w]?,~}6 PƠGyr&^˶)rf56=IQ3(ǂ{ F  #[S{]]| xYmZl]k?׬<2u#JY6󀺷B۷"7ˏ< ;t;wK<é9.oQce~Q.:W[ԒL,T\n\|7(HƾA9}/{(!A/62EzmJ&ıx/c'(E1Ia#)F 42 3(yvqEueb,x"^vO64~b[~Ԃ薂OCqi\ܱj[=qd (¡ƺh]^=\yhZJ eӲ[,G-KrV<]%74ĽBj#ÙP0r$Da2E~'s&=#CPS<8 x4_[}b]4K'kQ L@0mm/gh/F@8j6<3T"eMW˱>Oj88:WHnv}a] 0VDY]>rVo*C*.Kj_= Q'0B?~̡#{%KNaajLnO;5GisaS-/-ˋMml筺vxw;`;j *pԂE Ьk[}}ԯ#7SDCvg@j1*K?mp \|oVĄ)L~X~WǠ`aJ!m˞6ffE8ypBF^ÞLjMga۞ w O|:z]qXr*ghҘ*<#4zA endstream endobj 1386 0 obj << /Length 1059 /Filter /FlateDecode >> stream xڭWr8+^AU%,zcR=t/dmu ;sA~BtuϹO d d1:}<#q 9N%$3͛޲OV֏G؉bP!u7;0EPs"22|0`+m#4| sc<ӷ;6~F 54%ĸ5ꦴ*, I7}n  JŒ-i+VQoiñaĉA*TJ7N }NzZN}Gcc' <]Ni՜[vE+nrOKR'WR+ rIu&ByՎ(2a%-Y*ByT?ϋ)5A$}UIt/O5ɜBy4YUS.-98cUw7K>heRܶ\Ғq-rV-T94(V 6T0h]?G@~2.LWrc+n8SY-P%yZ]Y %9ts_&އ?"hF-7074͒(>6SwzLsTrQƈtj RE ]LU]0x뵖B*JXj&_Ӕ}GMw.ST-uxu7赍ZAUYDqxMr_m'DyW{nRTAsy9\1Dz=Ky( 8]*ȫTd%ȾuR!6 -U5)̦}%4Wr۽_z-c%I ڪF97^8'ֱGjEp۽ɏ?J#xnԘܹyqa6_I @knD߄0Za`eR!%EƇ; C-s6OwM^v5wmZ+߁}wWNzr?;E>PQQ}L.Pg_$0GGpiWgûa{mn2QQ endstream endobj 1405 0 obj << /Length 745 /Filter /FlateDecode >> stream xU[o0~ϯ2$ZiE Ml/BYv qۿ8NG\]^&ws}@>z;8{!E N D9") QDi&9h0M>GC$ CL sЈgc(NC0ֆ^G͏nӲ.4,{njC#D8NB͕m:x|/})ӻC~}UfdtꞟٮFʢj[}2K  DAx SgW7YUӭAk[HR7&.<Mvv]dbU"CW"ϗ4B|Meڵ.nuk6JhwfI?V`zdBUs:gIw]Jht܏0t3> stream xWKFWP!2/T&JGْ#  n X!f?/g7w:ɀr`GT:4UTYVT7wA{1!)"3Zc%ѐja-ϟN,6u* k qk?QdIQ%״xJĄF6@$UlefYUYTisV~(tr,?FGrqTFhk\1){rzTya"\Yzb>׀\db3[}֥A{N|hTc`?UɁ1;:(otH6OPjܼ?R4mu=ğ.ͪ(WݪW|wFV_[(Pd|֔sua֐2DL|L`1b1$[!y\/z)%6Sy1;MԚ5E%(\B8GM*mYO&zy:LeGL>6  NJ8,:Qhֹ:@1fUTY pă746efKߪ:I~Oe_$ִ"?ԭ.FWaM8deNH~߯S6vfeCbU'# a:28F 6:Ԩ=['KYUe4aoR Y=XsdƧlѕdG58W֛'' C!O800,eZdf1dO6{ݪQrm+5ecQj7wbDe> stream xWo0篈ڇGn4u6^JK|tIP [+|~;3r0 W֥fiuaJXa <9PalaCr@ȑ3h /@xQGjjەXB5*gߨ JyMQ;|bX-Ct'‡+m2nN'UY8X)ߺ^$VG?:h^?oTo҃NCAg}8܇N3HA+h{~20 #Y5iW fe Epo3]M)|w&a!7V[xXhBws endstream endobj 1347 0 obj << /Type /ObjStm /N 100 /First 979 /Length 2032 /Filter /FlateDecode >> stream xZ]oc7}ϯEIQtb``35؃Y~e+q|={l_H3,}f_nN&nY/~;|ݴN~9YvıA(QFKW^!^7߽sDžZM\2 ^q@#ϖC4yaMQ~GPtV!^>gD!=_#)IXOi|].NPc+zҁ$^ #IiC)>$ѡxT rT>bz=[gǃ-s=4 QJ(`|=znuTodzXnYFzR#JNngeޠZ,#&=zo &[ZQ0fg~I(7VUكԁm8w`g#Zc[^FRKYY18{+ ucD=9v6㌅s 7LI kQ"Ejqa4&aSҩuԺtj]:NSk]18vDu w_Qw珷ňyL*X%xp%a킏 ȑ-q;T:m 84e5! kH#p>(UX1+Cc1{pݶyk l(p(w߂b} 85{knmliR|kx|WA\*E;S NBni@CqGki>Ͷm1fڃ[[yp=RO`n֒;6Ղ{P[ b~2EoA0&|Wh*Oc4WN{y ҅–yK@cRЄT9%qUT=]OǛlĺ$p>>,?.fWgBNfW0Pm'5 J!o/DA9JRu^(ff/c({92ѦaofW~Fمc{sk7ϸߍݝq|,{'Яss]XbeTp)w-v3JKZTjmxCݱ*gPQHҁڱ"2G/R)yMe[m}7/Pu_Org6ԙ ctв EC?T(VIpx ؓEjI')"^[P!.:%mƵ~H5L8ǡsgܔE50Q<6WHKm'yS endstream endobj 1459 0 obj << /Length 642 /Filter /FlateDecode >> stream xU]o0}ϯRzvCT X;^ƄL댢Ii'N׸J !n|ι^ px' Lc 1*0474uw3+Ӌsf2lM d6!uOEBl)xdA#-**c-"bsN]j.rx@"䚕=?\O jݼ*54,L|QD1FP0 f6Dl$T^s +pjW^/*Pb `2%n>!YDkUb|q) >7< F-YV`>?s]6q{]D}_kR.]]&7Po8kh =V˲xYo#K~ 9Bk8b:5&{ =7"԰6}x}Ҵǂ֯=fY#C(TM鎏]3UĝPg_ڳRTjϔ9m=f3$Dbc*7jq,ujlo[ϕ=vWXf 1cq[m6!6ܧW:~;_tZ6 endstream endobj 1474 0 obj << /Length 1764 /Filter /FlateDecode >> stream xڝXo6X?T*F!͜CahX,z,MH=5uy;y{n,~;y>9E’f:p. d,/\"sz"s^Kբ}{L[9qN?=7P6葎/v8֍GߝlUFMU -Dh{ς5$ɮ>KiC0',خ0pII|>:JқrUW+LFg>?]_4[l&E6p/=Eni^=8@Lb}r}_Wt#hi~Ƙ"3 B>qA bXwN½Nw=p&*0{B7YV6=׵?/jm=cGNuM3WҾ߃=4ʲwȿʌ(1ē,FiUtˌ,LwV8Juugjy9pN_N&-o]&K`"wG BLo/y(]=V;F3MkP^mjA-QU -)-0p[Uns-qJHH`gTrCbwlik]О-E-2 z_W/߬WןW˄[ޭ;/LT{6u-yM aQCq "㞷HS <(}>sYQx>0(s="u@889B4<C2!N54/oM&ΐ#FaH 8áŸ4MgkcCtdNFȵ>r9HTYi$R^0Byn_*Zqu#-O?ݠZ.Fٹnh>YĪAfdh:Z3,=zSѸV]n53̋}c>65#FjrЄ ֝HމGu¬*A^-  #p̦k2n.t<}C}a0TR%PE vOT{fyLχi~<5*ʾؘJGa ˉqEa;?,qu~dB]:2LͪVV쑗rƽ)Ӣ$vΨY&[4gXbJo!Eq~R͔)4б\cWV{ֻGO2z)^u=(ݡY%t/k ./Ѡ/Q)b7U P :nq?5p_zDs,(ލ'Ӯh懜;T~:U.\)A 1M񠊹Sh1FM|:V~QtrzkҒp(,C NG }|Ӽ)Tm뺁:)[slo]bM(,4{jwX`U#ote*Edk^w鶢&04s厊Zl$FM@wx @vW2oUsl3dI\Uhce<.6n_"P]!*ԝ©O!3w=ra t>8 +oTkUjG `U itd͂0]u5H4OBlqM4^Ѓ#g<J0ǤQ O҅qeF; endstream endobj 1483 0 obj << /Length 1089 /Filter /FlateDecode >> stream xVKoFW!EIk(\ ĖUYʔ"=93;o-<}:LnB4s`RRu{[8$6Q~Z7/GcF\\#-ʞ UZf 7|?@O,6g)ωE'?$b5)5듪sE4AKi>dK[&0[^-UafzN֐QHQQGFy\x\ Ӡ_z [>e GiC` hf}V$EOmH endstream endobj 1495 0 obj << /Length 560 /Filter /FlateDecode >> stream xWMo@+VʡT6K4rkMOiֱ+0.V%4nzb;v̛tyCJqdQLp(! 4Xq x0 ϯtۓKՀ򹴓!%hVe#<Ҝ1~xLfg-A l^#2r͐,`h}>W|Ʊq|KہrHggn34O= g)T#s0meh1aE}0> iIy`9vF:Zz(a\6EP.j":-Ⱦ:b0V*0b02vYDՇ}<*,leA[0 n`r)"<} endstream endobj 1517 0 obj << /Length 1091 /Filter /FlateDecode >> stream xWKoFW΅Iqp8@bM$"7\J´zjg;+;oggW7s"I*!#ƥ$yp_GכuݩExO߮n䐕c6<,Ofo>iw̰\Z˪T^yu4"!1:?Hz{>x䷌>H԰#AF6jwqYm ZE9VVӁƙju/ /6RU\SM +7hF^D#l_ mZu8E@v ׭]UЌӭ CT?#$0A1ٸ_j= ZCֻE\Ax> g:_[V B(yr# ݷ:!4E)m~,C̏ޕ 'E":v#sf,TffH'k:˾2W/C sـZ'4_B_h iwu^nc%[ˣ.Zż;j艓A|h|ҏ7$ql By9&`~d43YZr0"1R B$]p|q;ӈ1 btQ+AGK_5>Q/p>eR*'fEd g2rb/G,8 /ǖ ,:,FH)x'(l2W+ٿ%qO&q4/U^GԣE@3>CȆ27b n¡n4KE- ]  j{8҉R'jk52v*tɐ쫧q7m&˝JG^X]Lv y~ 6ei EθsEu;a 4zA q%];t weRmb]h`wSQ?B2d߽F;O v`UqKѮYo&Gkʳ|ڇa089Б0?Fsښۖe7F?*S endstream endobj 1533 0 obj << /Length 881 /Filter /FlateDecode >> stream xڽV]o0}WX@Z\ıJUjeJFBI:iN=@Nz'##4#J涃$Mfod$+ð kN@]GVl-&%71~]ȶ͎Obx,ƛm߉ `# \߇'r6QG-rZ`!m4 z i^ӥishdJ0,LM+`GuҤleX+3~L3,y(ץ=q 0QkQ`*^ϭk0)e"?~Tֵſ܅]s-@Yǟ40!}q.:d7λ҇ϖ_\U8ޙ܌?33k3neݬ*ڲAޛ%lf-J}q,jk o, c_pu{yy:koS/$m/11ο04줠C1\'M$waֿ妗rZRa OoGi(d}9a.u WMTc53ZHXT;d^ffqhlmF^\2'ldp5%p$ɣ6bUw"_'՜}VrurYtFgBR)ɘV2Mr @M׬/P;GDufOASi`ٜjUt0kJDL YGʮ$¤KS45OiajX ׺hotå G#]C]AV ˪ 7SKlShjFPָ2~ړrFVw\$D,&\cja endstream endobj 1546 0 obj << /Length 727 /Filter /FlateDecode >> stream xVKo0 Wa60KHb(04ۥ6d~8vQtv2-IA޻w:P2H&p(!8)J &`%~HO̓@8Xi0Z)p> stream xYMo7W^(r`Hb8-Тmm T{B=JJȊ׊l@.Ǜ!3>j1>DQh0)Er&FB7$ |!Fsppd&l0q \ia]wK&yp }r?c*aXQ.NU㰌a5ryL/ہ |E)5Zv*8oɐHP1o*Ԯx#ٰbbꔠTn+~VDM@*TVvRl)`bJބ+%#C"$m#054XCk5Rl#FKc,NUx-m2$&Ji꣉ MP`hJpH SP  (PQm8D_0I2#Q\ᢩS)I.(VRX?yƜB@*JM)2ɑ" Z@\8 8B_H&)|*m(f+vE|\ ILe/g!`0< 7r-aads +0k'`trq͙zxdݻ9'jq?tKhԍ3R@MnlA 9fpUαh$>'lAUe`0V=fSlB.VSjVa Zj\#z: !T65ԖUG=k>F[:כhA9>y{1^#YMYq?7XfϞ$gdFcirt" U7?n,q5ͻFl+XW-GA } "}Ԟ+HCo{- a nEevaSq/ }i'X)'<׷ͶVص uԼ%Y J{mq2m7EV|5,!Kɺ;>.o.eoqPA .dV898a$-Z9$ WOhE&u%l/HR*oX-fK"a^w1q\}Ѫnwz,- ̓RGcg gސL +y%>wh-l;)'oް =26P5mO_~۟!F}0D<2bF5xhs3 U"U[K6%e_ G shpZiB+NZyS+_i=TI -䉚"?}ƴ1|旯xUt-q!-*1kL[ endstream endobj 1581 0 obj << /Length 977 /Filter /FlateDecode >> stream xW[o6~U$x]=-x}qBG$gr(⪲(0H|F:krvh,1b5M"L{%^fV훇0p34eܼ n^eueicw~o.< xzE|M-&ճ73RE4T34aV?A`W!Fe;糿IŇ, 8  Bul@8^xzn5=&]kq;m>czc">YtS5 mvay?y5 6|iٯmv|URr4CȢdNlRiV=ERjHO.`Dקa Bb1FiN:铐iOj0i2r0ragŽ@pdLhcȴfAqixݽV'/Sc'[1 8Ş>o٣[,vѽd+Ve endstream endobj 1602 0 obj << /Length 1134 /Filter /FlateDecode >> stream xWK6Wɡ61$%b6 Pͺ8B^zl%9,ʲvn HS|Ev累V CIJZnjSs~fq 2̈Uq;0%v҅6luK>~DIٚ  B!PE@ SE!tt3Bڂ#:+<87*X0UE5qȁ 9rM4ĔF]nS?dhp[4D9>h`4:WfIRlk&ۖ N@x˂n̓QCӇZ"kT݇v66̯wT$<.XV97ȮymsHpk@;l>W$h(+Ǒ0efDN9 $R]Hy`21+<Ȯmd 8^ 9f Bz BΠl056sYF;=XǁBt f7QSO6ITZ!kL21&ɣ9>+}jÌk|g lWݿkOI?塚p& @_4 :NSGoQ isBAND1g,})kP6%"ۧk]y~g i2 2r :Sv^5e_-deBqx2%믌A+RYkH{Zm2ٔޞւ&X`osѽ #3i/t'=` Bǟ a(H F[YWI_>68:o=5&߀%AG %6[>]g.ig!d U@uyߓKP9pVוSyK_ |*pKK0g3ts,xD4PZ]ob/Q/:aߪйX=pܯKlC&;(}HtGLDe2ٸgGόtwFIZnoG88pnd>*k Ƞ endstream endobj 1626 0 obj << /Length 995 /Filter /FlateDecode >> stream xڭWn6}Wj#H}Ib6}q"ӎ ]RIޤEd˗ED393g yqjv'[m=HosJV.yߒD2?f^Ѷ!.)>S~aس> yQvng?ʮ˭}&*j} \ 5 1X s@a!QGo4J룇xHJ<.6vb[ <#"lLs ֙w?S#_Ωd(s>8")p4gs7jA2G^lԨW$p0OL5 !gHS% U'U2{Mr8CPȩji\mG _{ #D9NpҰdÐ9UX:oK{I.*.5?XUBJ;3ctp;#ϒwaj#H9lssWv䘪S8$D־|K%( @3gB8۫ *bm5Nn[Uib|_`h*ҿ֬yt=ДMuGͬk=sk>h{eZh%>yc XW..'0擐ʁ&mYDlMF$F{fޏ ak~:bw wCyL"Σ {΄[ >@`ogAMmUfѿ7|t6i`9#gKӣ5=½ߛSa#`i3 S~h?Ԫ.W8T}'*J/Uc9zw}wVuy!O8.|#\E|rD  endstream endobj 1659 0 obj << /Length 1399 /Filter /FlateDecode >> stream xڽX[o6~)^b/Y(kجARIeS]-Ew.t,(x;zRāD\p@`x,y0ϳUT:}\{uɷO#KCN&E7ף/# (.D0 f& ]d<U@AAcX诎_it!Nq9FD5>qd9>|&U> Ɨ*m$ce7bn*o>hFذDh 7s9'%8ZY5YYxnl" =V5=jXݷxYllYa>'?ZWk W&\A:W4?"pˏR(8q " t,oWGC[psޑ@|,,EPzY#4xe~ڔB$b=%p\ܵ%[MKL"PBu9u-kkZ{2:׭i%-`%_Mrp$㝸}CfH0+'a 9o 쵀C, y^No_WvS\`0zl"8BeZFU7F.[04x`6/BGZʔ*[݈yԅt:iI7muʒHYqHF877)'(~ ]y^'LRNЛ7[_KLܳy ya,?\TP@n>g e'%\6=- X;isP-dy&TPϖA6ku}gϓ h᷵#Cg0C ƎFT9r6!>|MȉɎ+o Cb:&McU} Ki׿XE-H[joc:=6Ss1\`L-iij:^l]:ٗuV/8"_7lHwU5zb\8?I" .ՙ4@1D,lZt!,5"afċQ솷H?snJʠﰄ94#07~ADOdW].B endstream endobj 1557 0 obj << /Type /ObjStm /N 100 /First 986 /Length 2310 /Filter /FlateDecode >> stream xZQo~c9CI8$ m=8)P޻gK$~C-e;*>iv5~;#cd㌏1 ;aSxx> bU3C 1;EFJTl2ŔF{U<~_I%t!v-hV yK6DQY-'g(K-Lj9c .S4LA2smT KbtpR5_pP3=iq5]Rjd ATEqREwDMPER;3N^6EG{Z C3L h`A~Ge#Da5EqI? Ar (p0ɡ9־I= "k =*y5Lģ%>hA΄L hIR1%g0yWD&kCbw\ J2ȅ+qA@B ;6R{Sj4 >juT`K-l(# .W`0aXhJVKwNUt.8IA.qT\9GfKw}6XӦli?;7ڀ?hZ.6^au^fbn%ۇ4d V˳7/_}ˇf/[l֚ jQ^^κ6w//?cQX|0~:V!O?^>9kܔڰ-FjR~%K׾Cیa=GnDs.F{Khoi4B]vvʔDQ dAim@~i_ƒQw~}6e"!+eWTE$,Ni!6I^lu1ICb) CuÅP@M_V6`(f}5y \G!,Ám3=@\OBCx>.=iu7SbR(4jXvmp@Mh;T}Q;ڌ )n6\98mJi7| $k CZS/&HRr=jO{* JtdSda^7SQݒ#0/ag'ep@ 1;8AW0ԊCp8V'@Ԏio[@E:<O=h7(+0;''׋O'.ˋgjl{~R''V lyWŏ? $uW''r^ں囀׿~=ay7>ȉ9<ι[Ny xe[85Eʺz@JKhCL;4H7-iuBپTKP(.s+E9H[# X,dgye.ڔbm4__0z ZmZmZmZmZm[m[m[m,f9>.a+[~_2 !k%vE|H, MeW)W"}tk`mϲ2hoYvv9d_Yv@DhYUlmJ`Ps%dMD,_ >vo _e!l,;˶E endstream endobj 1686 0 obj << /Length 1055 /Filter /FlateDecode >> stream xW]o6} Gї[ À-^>6hLJdRVh{y Z >OFW#b Mn%s+ndc/OWzw% `z<]+IY}0" /?# Ch4f Asx +kCtqGw?kBҠ+A 14(20{-WQ9wY3IWc='6Jc.k΄vPXbyWPV/e<=YubdH'@%K/CB.K͋7_8APPVaiPWp>ε8l7 ~!w`cJ-4)5ԈSeb)؏nӰ?3 S[&-_^ endstream endobj 1711 0 obj << /Length 1282 /Filter /FlateDecode >> stream xڽX[o6~)Rd][(q#їMOPdі)E;s|:]}#yȧb;ę[e_d8U5~WQ0-q*g,ɺF%!zJ,}{a#!*;_̂n(zB,hv9 |؈f J#s; 13, ((|PѣVZI?mW;ȼNFٯnZx2}gAnYmF b4YjXrAFsz[5_*hܛvBNP J9Dj]\-6f/zx,El̀qk nG~N{2 GM쨧2m 2IW5#\=AJsv8(NK4^rLN ?+ endstream endobj 1730 0 obj << /Length 1632 /Filter /FlateDecode >> stream xڵX[o6~ÀCňHI5`X&,-&V#K$'~/EYQ=gC΅B߹s|ϗ3NŜphci\ΕD󓳰OI)C>'Gќf".9angi)(&YezQ3qUՍ(#ݭV䂻Y?C*j!:$fad|I*)kQegn,x[y)ckII:"e֖τбa_nƒ.!_w꿩TŤPCJ_{\?|7Ђ½ /K ňPu^Pࠅ%Zṇc.4}Zg Mg)^fU0aTK߯fഞ7F,[n>q^|}JxԛA/}ul 9>G iR!m݉cīTstxRvQ^ξΰ⌻qF #g]]N \GΣ\;DxHs1Ovn>K`;ahq o?H?|4[#Lz'#8%1nUcS : sq}yBO^?8#( c] .k݌v0Ǥg#z){)JЫE|oG]V\-̾D?ioؽ Q)S/Ct+ pT( Ez"]=Xٔ.tT2%z0p~\vFAya52i:iKiT=Q*L -ѫE/|.~o;~65Ka >>nkbKE|[AIX =# 7_}7^<>τntiZtg6)y!.T+ǩ1$x8-B80D f#ұZ~8.8rE;A}nF7j~<,du T{sc-' endstream endobj 1751 0 obj << /Length 1147 /Filter /FlateDecode >> stream xڥW[o6~%ERW![a9YȌMrel}">$ZyiũͶu5m "sl^YH C->2A$ҳ#1 dvjeYPpI-hko'P_sHG08$HGDҸ >,jT$i]n<>kba޵ו#栄<4wi[!Ke:mAX 9 '9ީrr6ɚ:wRMf q @p '=U3 zGOQYlj50$8I\R ׄޕU{G7#J$\m=_wǃ1h}l^+ġwGBJC\  $\3PNo*hi1 /w浺:KP}rm̧ڤ&K@0qoT3 P.{T\,~6~VflUkG"%|~x;L=fE4X"AO2 ȫ~\L'\C}oNR> stream xZmE*HNJ R)nslA3{<CBO.ӮrS(lQ*DC0ᆋl8qS͆JozS WLO<`@M7UC:_8Lッ~u])0BVGNu CLx!y+\aþN"2@ sR+l8I}Z N|rpc7¢td$#9է _{ zOT w3\ ?(P(b' FDA%T sq/D2> 0g`I&R?O3p/9R4=wILu_@9J14.15RxPGH+pj,;BPF)T}1: zboJ*a DԹI}H]]8j|8u8b޽ٳo;3{\'/囓ُE~݋f=|Iw5 $410[b]?ٺܻgfO췫g+3;5zjivN(0R~, r[Q_{5Ŷ ,bA/&vT!ٵ'HkM CWO;=>}dfϺ[v?ܝQnD}_y^w{..?ޛ<B0?6=ul0p؊@MM&HbRr,fy7Y/&Z.ۢe4W9*c9*PDp䅨%O.V ;=D cAK(hz4߼fB!YWOI|@az7_\^\n?LXvU3& WG(ʄNAT'wU~ݐFTHBȣEKdh@ 9="`-a%jK b?w/X,+ѲyNQԕ64eퟆ\ti+ ss7##o`im9%ĸ-Rd51[aCn A4=cu(+CRʢNl6ƼOF{$$#뗫gٻ7zK==_􏳳.]juݿ|U6ٺ[XO@_~iJn {čw&2䬻1'E9ġIfqr$(ue9ZSa,]=>j`|sjsc;LeQca_}nY}^Ml(ڱJ4(s?}k[CסPu:zj^Ҕ-`L&d uOlGy]u:Ώãu'a" 3' uJ]wmwzy>ڄ5/G%@?B~-y~"ʼn+ لPQ z;12ehC`M&XjGS( Mj捰aaW]_.Sy# PB 8C8O]ޟZ܁Tf,_fTVR9v`[$&Y8mS}~}ٯ𐛛A]\%mZMp#!H7p#!H7“VEO'toW%E&+}C%க* O̊ve^K}֛RE| c!0-{42?eie~ϑ|e?` endstream endobj 1769 0 obj << /Length 914 /Filter /FlateDecode >> stream xڽV˒:+T mQlQP`&“x)? 3O[ܺTj9>ݧ["hzx\<8X+QB0 b5Znʓ_/?<598 mUg;TzIVSo.HrcAA$TH0a՚-_:B?j r{b EJR"5p"H:큾|!rLKq['[+,}J]35l>ԋۤ65&o֏OjTIzr BcI^5( Te|Gڡ^|@+ 02Q~]2 !\!O$Ļv͓[MYYauuEE@DYZǟH!qE1/BK9e?Dg6Z1l5r6mM}6Żi .fi">$gW+'fw2 =frܞ<>3(t. _}L;hQ `Lo]WURC)&-fʞ7|Eˤ A{t"5r(mֵ.3z6m}%s\lvZ4Io,coԁ3]9|,ϳ{Af~ʍ;O\7Z:$VS|^Cipܰ)Nr0^) endstream endobj 1778 0 obj << /Length 828 /Filter /FlateDecode >> stream xVMs0WhC홠H ԙ|i! ;twA]M'@}O$uRM&K)DMWɃ hGh`bwRN%b\MLh[P 3ByЏjiwvcE6J` . {4jcњʍ*FBűc )aWvO5KYj١I E%v<t`K,\|I7'[H6a?NV_UP,Nc ߪ"O`IScU*F5N-mRJ/d_Fɝ A+GbdQ.1#K`}֙_8*$> stream xWKo6W@ĈIn{H7I"(n`$:v+Yy") (mpoY8Eg ųj`Al;#sE2IH;΅hoR= : %#Koj~'e/=O.:Kgd:{_"mAs&P0`PAk\c,D.3-J ip@@Z>jG6ŕc 3@I!,^|ϫڈZ?7?ȹm!$05Df:t9G2f /鱑'QMSMsܫZehfbW7"SXU4dρU5(Hi-Ķ+7aIbȆTrпM01HsOK=n۝qi)+ZW07rl_1[(josQnTkVa ͟XVw&@\C)l'5v&nQZʆ%SF\jJmn6oB{zt7si+fbV2٭+Q*?1ĸ9n+6u}lVfت*Or0> ,ru-M塧C( BݳF+rQo@>- Ulk8ez; \(ԉpCWKHTCbNÍ9wĽJG14fc |qw\ jA.EdNl!%3r\^u7[ۊ6z}}\D1{BS@}[nf"OeQmfK{*f/v52{]G.&mqc+ø $wCA@Bn|t)3#wRPE?<ƠϾ]GA444jcPWhQtLh=}vV> stream xڵXYoF~ׯ rO}p8ZT?vYPI;{ʴ 5 73 vVvM~^L^̉QY9cļ AE\Mϳ/fy0a$>G&x=!aH vRсOq<`;oݧ>8A@}@B6EqD:og?tRO盥[jOgnyV7Zx Q/<&׀+ j߈&uUc+}$r\ ҷ߉V (y!v\NQ]HbSvG"ǴnVOOD e/" ~ف v}=q$ Zd>ȣ'MßNٓyoH7 &wcjSr9f2a\ghSsȩWNLS Js`g!yKKH0lC>1RqW [̈?Ump$Fp+ю..+Ny/X+얗Fom~'l7e2%SǷhhFEOފf( 7|DixX B}|l&)z{к]m#Z78z tѾilZјcE1\4$^PU^mS)yU..dvJbWе3(7gU!*px -`{l =x-r@[]e֠L:L|!e.1Hv!G_ 6h[B̚ MQ8jL @+rF[x: f6_JP~C;rS,tcU,`%fatUmvx%DrSUy^(.Kn? NnjMO۱ 3{Ժ?mHwziW?Ǎyb7CChOs/= endstream endobj 1823 0 obj << /Length 642 /Filter /FlateDecode >> stream xWo0篰Iiq#a-n p8` U ] $@Qwy~>l S3;$cȉ 1[uǮGơE,<j *A˜le@e-UȪ-7e/mZ*ѷX&Q}QOyrJ(`brmp;k" ĆջUXs@76%j@5v}a9ŀ[ڌ&s(ju&n= J z: żg-ahF9 ]EŨ5GPH]&bhE9Jq駯z|,CU8 jEOdT4" xAn,I]ޣEF84uwl{yKq$8ZQ, gm4@W,؜ [yQگ?E[x%گ=o!L>߯7XLYCN]qwrd+Ȥ}ݻZ endstream endobj 1761 0 obj << /Type /ObjStm /N 100 /First 970 /Length 1598 /Filter /FlateDecode >> stream xYn[7+l79  m,[MR E=CIK+u4px8K&پѾT\EM";j8* Z\UPԋ!d\L`uMFF\>@o 흸 Sr0pQTRz"HQi+A60H`I0$NR)~LF(sc)1`#ư(C6&˵$K40!̘La aV%P1 (ZMQɥ.pR[vF[v})ؘԖ=MɖrӌzF!TblivSBb G\l#Vi8&j  $h+r6omXaFVAIMër0(6$aєLˉWh\0~ҕgdiAX{f\O ڌ5$̠pHpڀ M[);(mPThbHNI-ŲICo)K-2"2搤^;EDVv؃^N&zm#Zj  tI|t_ )܎hfM(h*ΚmN~lȤ^8){##wGp2>/czeV,ԑip\S.Å.{'cHTg+$ykg/`|(Fo%hC R%Z;MG6-;ޣt\_Σu :Kܕ ;zwC'F^]us;2JăAŠu;rH à|):%hG4rvq8!v w,]Ěv(!aМ<_?bMCqEaXx|aTQ:qf"Ȥ76^p;y)t.Nk!ni#^;ikpxh]했*`Qxgr2Hg>#Qo&r'?OПz,؛1@'n(E}84\}AѮZLkl^&hA+bP`,y GIg6ݣאyK"+y &|mlWks D}: j<+Y#]lG#L4SPG4E/U&->t5$/runw"JunqW5>k/J{C9> stream xX[o6~ϯ0stm]lZubӱ:Y $9i/Erl );߹)݌ћWb "FLBh-Ƴ<V֛bU]~q5ݽ,(`s"fuNiD)9-Ϟ]N9̳Y[f6uQAI+Q \'fgф8͂ϓ&)e-64"m.J 1IRNh Ɯtbn>B_SK XPUdr@%P]}1Qs0G }zw a9opL'nFiQ%"$ .~>8-;co۹|)<(e #lSqdD ]/J2㛝G$l`Sw@2{Z ZKᇢQv1=솄12ȫTҀ!(GQl.v*)*yƵ%[ (k$qm#ìQ$S[;ǵׅY^+2/2ˬ̬ᩞA|71MC6 d!{! [j 6 >7D+feR^O9l(A5xG-ۻ˕7FZ;%ؠ^V]RV”DN@zqRɵzJ ϵ0# 2䵴6vNvLCMcץ卬-rw֐ˢ(W)JYM\{w|".y%t{ӭZ)E=d !25QnٽjEzz-*=6VI^ƐIWL,qUGV8o0v um=#*;Q<ʿaԀ1tɺ͔na6.(LQn0Wc --PyRl;5W"cE(6ȩ<-Bhc 0օա$ o;`"JjE^GbE-&Qygֵq!v2dQ%"A\~8948R~Bwbh?0(MI!zJY;UH3U)I:Ap¨=ɥ (m_|[i@sRtT"F,zK=߽PU6=cv6au$AIF P1ncc#}j ͷM̓^JI>Grި.ЩZWb(ܴ+%H\dĉ4P5#zг?n>"8 ӽa_6UBߐ՟T)=5ʡ4}#lI !y-0).2ã`MMF'<7[m!\Kn`P#&z!䧘~a8AǮԹn^=MOd A pJQ}͡BkrVz4o)*7UD괍}*| { <żç[h^op`ꑏޞChOg}HWK[ endstream endobj 1863 0 obj << /Length 1747 /Filter /FlateDecode >> stream xڭXKs6WЃ4x$&qm$/NL)%] HPDǝD0Xng/~Y^\^El&h4[nfch"&ffΣ_.!%̃luN]`sU%ư4\wͽ͑ $IwE"pms/moeFrAn+&mлyUיKŎ$S֫y푎(d)oUPUY7LpM^[YTyO8-z-s;^(ϺꅇpK,pn<,iYwQ!A 𼟄@$77?>+1oiXm|]'饬ؔvp)/7U=n*B0@EDǩyfO[fݦվSl6r:%È-uBy邏"j alodOZ.zdfu6mR_PH#jq[BqD rW-VeY"mVvnƶG20MvV7/,VZkA Q%x:Q,±,3]ۗgs\[U/mlA!EG2mA_~ΗOb8f ^ﻕ m:2SKRό .ւе3¾6\DǬ/ Y{޷YqPzz]Cz'ߜD,JDБJ:.! HX[ Э𩭺;P@Ff q 3dڞc?LwΚK[K`5Jw"m@R{3u !8B$N0ºO=kf7A/U~^!7=h㧏wLj]v,Ik`eqKrzt7G2 *E0SDgd;h炑sC bz at a:-2~]W gO0Ȯ (DOY< ͽ:"lQqDTixjsTɄDƄJkgTR[u 4!c4b<ç?Z,Bh:qg!޿r u \ոLx2quZ{=$Bg-/Ī endstream endobj 1870 0 obj << /Length 939 /Filter /FlateDecode >> stream xڽVo6~_A/=ؒZqey }O$K&@:0O}w<F]^/g.G N$hy(! X-Si~~mmu|B B`U2#?fDhJ* Wh>}!(7jF CW:{#D?JII0em8^vB 2hҢ}M(0| Mp"Đpm*j1cB5Roǔ>3.\OpN};  k-s?J—!<2lZƑhֲu޶Ʃ}C:V}ϼ~Z-"XPjY̫ _ty. f*Ά]gxM?8Dɐ I jS׺GR\@.<-{(QQ z/Lv8;Pd5fBuq]YRS* \E{ 5H ay0C{.کSz,m[Ǧl?W7)+lw]<> stream xڥWK6Wȡ23|I}$HIi r)E]9h&gy EiL` ƈ8HA1K6FbcۤQ";esYUoeAUٗ31Sht,hikP'5xS1+1qr p+|4 ~{:ö#Yc=gFj\,$ᖅy}כGCLG)vƜNP U>ܵ_jΒn[KucYf~Ύ&ץ[=1d2vA`Fs==;RC0BM} Xfz宬<['וn^{M -6? >VꤥQDa1gA vfhFQ}c/ǏO#s+]K p?0իɴ(\m1D^|w  .V5NfwC橝SK˳}$+;"':J}cBs [ߚ}1h{%]53HQf*а:kg平!Qűdb C0TBdʓ) FAp<.15/rt4+ga>13?\=2 endstream endobj 1901 0 obj << /Length 1027 /Filter /FlateDecode >> stream xڵVM6Wȡ2POHK*67 Z;C֢mJr>;)YJma"pQ!N~\N5'!Wd&RB(eL{ytViT7窻EP:@ + u'\N0RZJKa@V W6kqF D#J 1!vD{{}`YntKۧLzN_~ \OWPE(@Kn<9I8 ȌOrRIf<۹C7vuPa.޼9*l8Ӏz.8rJbC򘻱!C&sS.%qnIJ2HL:E 'H}Gn/p,L|)@юF yLDk=b6fo4b?6Aט4r0ia#̸`o"!ljhg4X½) woKw}JKZ] hk?gr  ,&W~zΞt6uIu?eyQJl>3ٔk\>}J7'iBRnM#C^Ѭ|ZYXK|۷Y޸z@#. y s`-͟&f>R lϼw-C[ᝆUDJΜ uru.Ma*b.-Ɓj8T'W*+3m.FyZVO>/F́vzFI+آ֪d/u*=ن")vf%FV1[tJ}!c4rN/.xq|?ϏQz4׳ụu8gϬł?VjN߮cЭ3P_ gDrON*s7i8qWNGӣk܌g週ʯI1<0MlYW| V@qV endstream endobj 1929 0 obj << /Length 526 /Filter /FlateDecode >> stream xVAo0WV*2 e ?c,`Mnmwx҂ևd2|d@|׷r qd֗S}M>͢` \WQ˛cnl.vyt-N$l㓓3Cx#VgzBoRN,mio4Ĩ$bH؎G<%]c wEk٣"P![}gi{@]jwz|X>$nVy_apN7L )/rbqwQW`͌Ki˲N"oc{u%؊ӔjDh'VVQ1]OѤz| Kz<D<ĴK5-q/ANZЪ)mZLEE<#BL:h[P7Z Ᵽ;c`)UsE߀$ &fO&1IuøgS3{(o׋dX endstream endobj 1933 0 obj << /Length 946 /Filter /FlateDecode >> stream xWM8ϯ@& a{J~hM={p3a I5~_c!l/ytv.<'D!Y1|BBg9o>fk={vλ>&H`Ĉ\;xF`Vz2 ώ6:.dȲA,u9QR>ء )3.}&YɅf^_DGz$jLMRY|"֏L'7vkBfe<ҷǭնٛ=,G*b0"j%+x66B;QjuME~N\҅* :d`fb @q, 'rRU.>7׎;lA46F xi!o %:Zy"Tq\S?.h̑3q'iHFuBO(ck??Rr8D &mY~F.wЇ"A]1#x5薽l85h 8=̥ am]i2MڀGAxSk6I`:6V/!r֚Xve6t?|Y\UvląJfhgŌ)][yeJ`#坕nXF ٠N#"Q Uo*It4fDD34~ uQXw91,%@~;Q6+,mPvV҃po nd%[> stream xڭWKs6WpC&w=8MLl7=(LB:|$D> ,HeSo?p˱~]^8`u RuZyᡤč}e>hj%7svE bi>ȳ#nw̓ x҈ EҔf]̟JLͮ`>PM}9'kE Ӧq2m&ۿXUY/x=~j]`ٔ1vM}˷b[-hFtzh8qP.]N^ N3#]02fr١񽨦]8g"=m:Ŀ42 ,\lAjASP_E4O^ B; 2ZjjRUI)*vԪ2eVNLR7oCll=9;RT 7cz`ݪ6t:BNê-JsKux?)jRR|# UO)oxnJeƍ/͏ "hD$Mf^HY.uڶ4EG6: ^ Rz+P u D:BTas !x}Pk'ao]و)(p۳XXམ$ϡ7W<o/Ց~fPi$xCL6 2;ja NԕgjqNZ&;nŮf)@c'FH+>Os ~ΈtJ%}UΟt*+((ړ˥Z2g<»{txt!._w$/nƬ◌xwwgDvgʱR Yx`3=6 {jph Ew.Pp#n֧za3lLB'DIqb`(;|ⱑ' )I޷N7~.llղ_^NaT6LBTvBORЋmƍ({uZHW/͸?2 endstream endobj 1845 0 obj << /Type /ObjStm /N 100 /First 976 /Length 1613 /Filter /FlateDecode >> stream xYKo7W^p8pZA;(>(U$7d[QTU9i3΋/3Do<)PJJd(QL Y 1)L)))(8QqK" ^((`Yt..!R lT@Z9RzsPS$lp6!ʺHDg0V%):.GPQBYl`H%)Ie|A@U53Tjkj,"R)o#&Jj"ī9SCCmE!Na*Jk DPj] YTD0Iy &xlxa~8lY rѽ#PjVqXU<$J=Mt0+aʐ@Ie&z(xQJLsށ:=J"Ⱦaea9Ȉ\ #Jd$5c+bu2̐zd,Y+I~M" $Rl{5F*o&.bG X+~ |. Tʐ@e v279J#c q r]²)^<}:hLܜ͋#Ӽ}>ܷG0|?4a44bx4k"KԹW9Չf3N>LZvHPOMPKgUAsrn^?]N4hZ庳ׁzMcED`7-g'yپmM|w{V?:H2ܬTĊf$lUU;_GT LVЍ*ElyS'9m//zT]ARSQ*'A9:/fDlА"ur5m{*::os슦lF_C߆zލh Hs/b-?%&i鍄MJqOUyeLzF2YG{M5C I(qvDG4,L#s[.%MdѸ#SG4ᾅF_c],7 ݕxɿ" l^jP) o%#Kr[ڋRwpY#Ѣ_m#jC{`? gtC;r@g! b$ޞfϓ>%vNk ~"y?h$ΚPetD,H4i {FGc/B/; w@[>m͆7Gf%ln6H?%fP/Dȏ0SLK=`fSWt A{AZ5t2PK endstream endobj 1964 0 obj << /Length 882 /Filter /FlateDecode >> stream xWKo0 WaPlm MvZwlG Y輪8qZo,$GR {:NO.P@ &| 'B:Oyԓ/S-@XbW"'*Ǿ|9beְzV_9x!nv 2H!{ؗZ3#1 -xR/*a$g Fˆ,73 (qOo=WU^H=? dC 0"< Ɛnnb*Uomzy3>zZ=xfyˏ&H/O!oo/|E=ix({gdPY~ TTO{hrUtSg~),b2=Ԏ#ORV<w"lO]oZqw 182Z.A-6w"DmHg:5ޜ+f*>rU͒ Úԯ䈄::~B |HAN 9&Н|TC]})w;o@q #xh ǻc Q PS*K)ok`N?AF$%]ev\͗0tMW\0閴&] ]yn Y?ReYϩ]jj'(ty 1SΚVpf\EPgknW|#r+$c=2[4͚.i\ vTʄ/XTmYfE'?M)[վ:j\xA-nc7ھ+h\{xfqpp9 1 endstream endobj 1970 0 obj << /Length 1206 /Filter /FlateDecode >> stream xWKo6Wam bD{ɢE=A@tBINKփnǡo^t=x2IxE$((Ron' ~;m͈Q1Q:.DQWR(0zrIHk%^Fz)s6q0YKz-*ܖZ<7J !ŒZWg47LNR11DY 4'OSOFh[.D.zf;|R}+z-zW|kIlac+WbaPXNq0YyÈ!ifn/)I$G(ơ !Jcl#S<}hZ^e|R˹0EV ^0g1œ@1f[Unv^ #xΘ89SCQJr@ȵ^|guOQ"[/ad5` Bx80Mn%(TT@+N]yV;.8(zDC#Jh82Bi.CpidbpQP M̭C4`B;Uu:ߜjwψ*2Nqiy?j:\ 4PC|{/ O}1;C endstream endobj 1977 0 obj << /Length 892 /Filter /FlateDecode >> stream xVn0+PR(hI)m^\`d&V!ٮ%]ˑc׹b=gI="w2 8@;D S pFTޫl0~9:hN(*„CzĂq\:,`:q}x'S%'?Gi+KeF1 `JpYup:bfyg2U)\be%LH?<`e@e]@a3NUz.x7s|j+NԃJ2s?3ע86OQ"LHjr~[EyWoLM\RSA;hˉZi%Hwt5 ?,ZƋ^|tSilFbWɃ>yLe45Z界{`0by~2z烍X6uBXs5gj렲( x:+ΌMjʭsIM endstream endobj 1986 0 obj << /Length 706 /Filter /FlateDecode >> stream xVMo@+Vʡ ~/Tj%Jm^TIaw`168Tꉅy MAgއw|8qB[D \()Ŋh+_ztq|-yp)mi66ee˫,g*FwuMP =֦s$ 3t}i5|!SHIQ-4 )TΌ B&dM^d6ɋN5#͒=D*ʟU<"ğW[zvzs;yؒݾs]1!UXp=bɨ%Y$ԭm@SӴWްZw6~ *m^ 1.vf|}bo߱U~5X4%IAۇN]=n]')yVv'[Ȼ P'[Gh=d=kӧG& ~ݩ`s%8h/LR\۫9.@b60/3L}MkN6"X/1q.wf!"TWPբ endstream endobj 2007 0 obj << /Length 1066 /Filter /FlateDecode >> stream xڵVK6WȡqI)H6$usq@ksmJcEJZdaIyoH~dtuH2&. BMBK|-lFqB hA*2" 貖}]`\%巵ޔEgw1RXC?i;V%q:3AuE!^)ѧ'QPA J @۪R *Jú0)~A6Ծ0+G)TES*7ƈyl"`syLT5vC/Q-~~?BJ%ZYtU@x¼UbQ1B6:~oаRd3+#Shj\` lmpH^3Mٿ')dKөjl*?YjaC TT1(HҶP?,7YƤ }NE@J~DId&0Z +=QXDk;IC!1g ńtA]ti]Rۚ3id9, AFX]dO{!eU֎>9Aٽa4LDݶwSxlH)7]O\`{H~A>g?Kʋ<ۦz@+K..E+l> KTn!iE(h!U>o}ML.07HO> stream xڵVK6W!Enif\6B+ӶJrԃ^hz(k^|3G̙/1 (s"B 3_8.h,;emk'?G>`?-&wYO|ⱳoE B ;7?{{c#FBw^}Pɀɛ!vzQUk|+*`Fl_[v!V-a$B<"* QUmrc`0)܋$=g~-5حDQz$td3٘B.gNg(dTke~Y:%y#NF쪤 uCiu]Y҈z7C,$"Gqrf5 x&@ږ78{Se GPE/mf1JfI ě:?2uAD ^9 Ԋe[wV/AҧLLԢV U44y<>] O'4w?R?V&{ʢ > stream xVKs0Wh83*ɲdP e` m ҃IăLɒ];q4S*afۑuz]FS.ec >_DL.FN/Xۄ" /*]( Rt.\mr fDeѱޔ@؇8M(9O(mxhe N %\}2qFl?梜\͌L3+Fh'RP &EC™´p&Xv'da%3ZW*COTxJS$ `Q#kmi Gֽ%nSH Ɖu{DSnU*SWcpm}ۙU)#eprBJ-u}7coĕuuR`n~)*i<"b2^k<4 L Գ^3i%gO)d%Pjco Tk0XrP6s}z'Q@Y͔UaB GoPyJ+d0RYܽ{1k@bӡ#Q#y{AGvB؛?>%ُ[#?W7 endstream endobj 1960 0 obj << /Type /ObjStm /N 100 /First 967 /Length 1472 /Filter /FlateDecode >> stream xXn[7+l7<ym(,Y(u@V{])ʑ\Cp<d\R$_]%W r1!XrUv XNN d,ihT i5pbc+~E0%-nTc!{/t.~4h8c1J5eȌ*l!AC C2#b8 :6 GW2$L%xd9ORigk Q" (eQdT1UA0h5 FjPcjʪcdcHsoaTx6_Wش~9z]N4go5} }:.ɉNQհM;EBj}@i]>(3dW>ð|v|pnɩ^L>.ܝMbz2Ætqc%]lh8/&7ƞM.ƏfݹO(0K(1:OZN3vl=fj`4<jў^M fɼ-^? c{0{.+J3z/Q{| ?^ϩ?,.</?gVyxєIVB*T>k<0|oscAyd.y!(3IҊ xIa݇ºI"--1)Ox$_zN{xu|(U> vԋ)#_{ >3V6q uJQМ|=Iz}x;}h{Tt4}ԉ`;DI'k_b"K=.Y~@ rȆV ]j-p]0G`xw:{ln̈iݾ/,Wlg7jp&Ik|IM: 86bՆ;^̯>ܚC=.:c j]g'&7bv3 Qlek&]_m7e}*ໞQ[*4ܡN&!zwiw>ݤw(DAE> stream xVMs6W`T)7ACZǝjʹVONEѬ)R%)],ȴ"M>{ˇ$#:y1yu8!V"aD1Y,4h%g_37U[ Ӛ`7ղN;b;KE0&zr%|kr/]t"q^ɟ;ñ$ľ FA FTZIa&J<btN3.&tu-}w\P> stream xXn6}Wj5W] EAmN_6Ȍl7EЎ,Z(932~4|X$a0{ƈ0A!K<<.M,zev*(szjDԔ\ڛ;4g,caZlrg$P{G(i1#x8-LuQ8="ģCU.}VEgo5#1 '6ҴFEȳy/]fn/=V(DhL:v=~Q1͓tDiDP'Re"mܗͣy-Hy5^8h Ƹ HXn=A'0rO*_5z\ճiJKCqP)ޘZyi QĢ,j E%M=aۛ թg*kҘ}| b/JCÎX,.e}N?Mn/&w` (?ɦ)r.PV>"DIe_K4dmN=fyV9x Pˍ`E$]z58W   d&" zhqqW4u*DM!E E(N*F$d{PiZ%1* EP"ړNYҿV 穐&\WfK&av@S]_%ta}|9gj[=up5`:=ljbN|M(rVRHMF1]ycj+B;mr̝֦TT !FsP:3Fz=uVk-&M)޸ݘxc ѢsȑحouGkۉm +Vuh\:n|+?}L:}C8>fgL7ܕ#DGsQ]}C|PXMJT!<Db=MO~1]bj: BʗG\eaL[6k+7+r endstream endobj 2078 0 obj << /Length 821 /Filter /FlateDecode >> stream xW]o0}ϯԇiô=tZ)*I#NK HwB0M}ۄgDu˸w~sg>O%s#I)yH6xϯLA,8Ŝ2qWI`_J{OM9D .ΑRpgh^kr!6S.(=G;QA 0U :#ZLUO9*0⼍t@ں4I*ErY ްxa}(u6QejUdjUZ[\{6}u'mV@G#WG1gD.8'?>v|WXvf#nǹ_zkD3eؓvJ8)UG<_`}t9 1' ,9L^T/g*s Єl0!0 6?u\;=YE< <_^G Zp{s+35BCLa19DLhpyeF u5{mbauMʅ|B*1k,.eDԚV0٩jҏuV;%y!sߪN25#/%fB̘IFͬZU-JKz|qf}.ӟ7a77C'ȻҩCa9P$jWeUcԏ(I>ʼ%; hW_}}` ДSKŏJ$k*pRw#\~Cq6۔`mq8zHmZX]{iof endstream endobj 2091 0 obj << /Length 600 /Filter /FlateDecode >> stream x՗n0z 9D*UzI&@zjqz$wX[">iLǟ2F #7ާwqmjcTHM ’_|ZHDWQx@# FG$yp2uF$oxJF$Mj D+ImC֝tpj#0ܸ<b~<UAYb̧(rA-@핿[1/tzΪ3?/FUH Y}j4Jl,=:&T*PQg5uiwx$BNW}FQ{Kqĭ?3K9Sj2FGJ(B8a`)_[qn^Scjd.Ӣmmhv42u7>;xӛw.w0t]7"BF dtuG/RgVaujާ kqo4Z_p endstream endobj 2111 0 obj << /Length 878 /Filter /FlateDecode >> stream xڭVn0+P Xڨ=Ȃh-ӶZrM9i#lM@R,o3HtfX/OE8 X& D RtzӰ+ E`IL ̗ĦqXGϩGW_t'{ L0w=AiP<v\JJ8q?m#mꏍ7r(njDK5Zdr7/po v3GCV_ 7_;C9s&Qv\ݰM*zm梨#>Hq&8s68-M*`E VWW䄻&l'd|& )1RNo"k%8ۃ">̲DNGkLk FqD.j_U͢> stream xX[o6~ڀŐ%^26z{qزARINÛlڊc{)0%;߹8X8mdpuˣ@ $,1XpBP`2roe+Gw?n SЦ%yDY#Zr̒zDp^eexǫ[v*E Jlᅨ'HaҠV+㧃Jȭ{_-?cDE\8^\0L$E-OXg9ք4ç]Uji<4*{[ ƴ[&`W\c-MVumug2{&juF$1BO`ȰE "!UzF!ۺW='ڝy;oAqD+Z^; $H FΪժ*S4ML" pU5mh鯇Tvtצô3]M XPDHıg@Xγ6Wyƌz{%p|> stream xY[o[7 ~#%AAwA Iy فtG^N[$G"d.8: وX$gQbD@$rq9r5lt%)Rl٤J]KhnL  QդD8VWq$l1;!(5Hۤ*(5VL }F@|UB4 RK2RKUHȐZ#7U#8l4ΡQ7:NԊQJdJjXPT6"1  q@1d"NchX/F0h3^MsWՄ nK*6#hvrٳAv:9݁rݻ0e}:ab~4^Bh2V} puvۚu?#]n|~zzjhGVВ}B}POt[CG8Q 0C(}צ* ֍uzQJY.zZBSP&N84 UۉR}̴LǓYYMɗKtBj:EЂ݌"-Rץͤ[.w--Q_$ eS9du9|nh Wv*иyZyƭB 4Q6vą̛IZj$e$uUH+[ }^}EqhK럷ת~hէ%N\cJk=ltX}Dtpg>=\_O޿>UwQ]@S)^R SSzyBbLO۲xAEkߒKF/lwMػ )Ks7ȟkd.#TJGw> stream xWMO0WX #PEB (S$=NP$%-B%Nv7/y3k( "D sD0 $ *])X֑P 1q<%fLvs]@zc5(-k0cꇍ,:%x$^1Mjns A ApQKQ7|m;;1 xgOT[[iBp/iČ^#kS u(,W1`\ (S=%2C?_L&Ĥ/3mE@CfYU![ӮIZ.-.:3N̝7_2WO1򦓟Z=[] |e[䦙ox[(DQN(X/6x4MbMz {9 n+,36rE_^Uޕk#a@ ZOʳWN3d endstream endobj 2148 0 obj << /Length 1341 /Filter /FlateDecode >> stream xڭXKo6WCmfDm{H@l\Nԕ%Uw(ˎBy|f8t<ayjvq͢ CYB` p&%Qa~S󼨞u2\OCX BYhZ2X4X\ Οv[Q{^\S:1%~h+KPkeX8iZKCk0)hO o[-@uZѯ*3ՉMC:Άw}Zswg7/w ĂcƋdI +ꊗz"=-fpyn1>D$#h 6Vt?j!kQ ,1AYL?9Эn; VyTTrʺ?>WQ\kދ|u@әg|qTEMFWfbg5_ U8 x3oJ3y9 3B'N5ҰێͧGS>Fcon&%)Bp|Wq?w6;㪹ma\32¯3+6mx71I]MSy%VѼoy5uW|gzROfdV9T$횥ĩj85u JQO'zˣGuV!0E9(ֆPb 0i8_9{>ߋ(p$wE(I:}rg?!L 8Wu;IvG'Sf7&ܤJt?nK%H[O 8Tٯ@HTuf*$(Il!ct\X\HW4r8|\,#|$=qi rUژb Ebh[^Vsͷ}M񴢱gK?O W.*q,F=5pe M+cLAf#'}u5o[N5!{i5kUɀ6 p/ c0*(KtPHʒ f|zwo T I3M{Ad1m@JxoO< [']& rKNe(&ؖ0ݺ-~\gG]7'\4)s;$`pjn3:e9W,ImZYF[$պHvRHe2Eκd!(#CL*"߭'DEQI2D/!дƗ_tj}l /3㐘 endstream endobj 2161 0 obj << /Length 1156 /Filter /FlateDecode >> stream xڽWmo6_!fc5Q C%ljo_||тlq`( I4 Wd@P9ISJ"DDMY#U}ˤyc0UV~BpŷS3>N*dJȰ߮sb7䮊AgD|uBU2:>zU&^}Qc %(:<~کh=R(F cA;%ph-` x?{#-n0 ]`dՖʃjJX/E.V/v/fWI3!ႊW2xcL-CX>/K[ڌ$Xv* k?9Dt|t&DV;YXN~ vW3&V>TZ`P_A vX١1m{IAtUVʭX8@so<_{ A` KEI˶bfxJ-}>UE0TwJx'ye.˥* 򖿁eǁ#`E@/2u_6F|9gQrS2IiK Uu.D{y8|qjH+S$MbBEo=*yo'U7nyx Aؙf[7p<I2E+e. ]AAW5HݲN<"xH.` cNU46qU c„DYqYPT+Ej|Py6gwuw +JY# IYZiM'_6iB:P 6i*~*'hߋZVFhOhRd|e2~gOC:cS$~a6 R1)$GQ+ؽt;Yv<] iO!Vb1]koWmAǶrF>0P=@ӽ  endstream endobj 2181 0 obj << /Length 1210 /Filter /FlateDecode >> stream xXKo6WCmfm[tSljӎ[ $9w(ZqYFÙof>GrBFZR9Gcĸ)Bdz4_d[x7z~!PU)mEpdiKvV Ϩg}rx~yN#X?_Xٌ2 q"MfƝoMh>5['kYőH%l.o4\&,O5H:zFF Bp":o!t}m/R7v߉EW%1 4 y}"{ۆK3qhh'MFLAh tt4ޜ\Q,'9 @zy|UKz=-':ZĂ#/yw&o~r#pSC:!x[X/ĝ69J\&VqÁ~B,$iR0yޏHKO(bN[uR^axLa*ڍ[o7']v`ZmBLt1=Igfuz0K O&NlRzSɡ`LCaI1ʱ=lT6Ջv P1;gy15$]Uw7Mvś7T2*|6WAj0jWBs tҦ;,%tӸתfX$.% RJCJTVh:~g]|nCԷ"fY}ĩR~ǤIv3/=5:rՃG7kkI!eeߗs8ܙʆ jfJ]ZTq(3'Hq%c.DkFpgbr$Unšv x* Jckv¡`3:rϣLxg5 :eYDꩯg9L  dOQ i,3߀<@5,: ۪`S֮Rw|Ij㭳&s|&/K0:S8d-mE/yEB[f4_Eh endstream endobj 2191 0 obj << /Length 1055 /Filter /FlateDecode >> stream xWKo6WCe ⢗I(-x{q}Pd&V+!Y*mdA15EΣ;'?'oB$B:>,t8(™7IEG GO{t6;uh[UN{qpؤFȝS{xO.!PI!y [&M}aq2DZ4&- s<ͺ\, CS)k]ʒ\\,Sl < `^A mh8eE]!"kB ›( ڕwC%Y4%1bF-"%vޤ".ěm/CNOޤf'๑M~%?2f 6 a^-#Jne^>^ξԽ U~'?u5DIb;+QCZg͚; Δ s7ŷXwڃ.a@GΓ~1+w{'c<Ǎ U!S5ahWNt⌞~V2 6' mHcG \ELځ~w|Үt CXzWqgE|[7D;wYِ_ߒNʢ"-mlgk_fʙ{9^[YuzyڽoK 8oGznW|NzqETlzz%c1 {dҦVfoRoHNS<ب'hˡQ+J2 Y:ՊBe8p 4ug endstream endobj 2213 0 obj << /Length 1199 /Filter /FlateDecode >> stream xWKo6W˗$r&[H&AD$'C%K^۱ {1Gp4xhǛ41QJ1 ,yxU=\U?UEͯoC9II(uY /<''P]c)I۬*3agK&T)T}ә<SwUZwwʴ0K$_1+n -|Uk^1Lg2ËS-֟Qc3nM#J9pG(J$8}f 8@? <8Q9 e<,׋> "&ԣ|m󼩶/%*'mFlCSC(HD$}uiXOH`830F@yQmz;lM.0>V7_8SG Xز R}~$\ڐ"mr"rdIN# ug7[%et3) ViXȓЊuryzw0b!ESZ͎l`EWYPQh)7m1z۷[cս|C3_9,hkI%Luv:C5YE)qǔmd5rGį]I4Vpūf$f/#Id~K%A'BqJu6'L=7X:KHbI2RuuU9_U,Z;ȥC' -H|1]fQgOG( >UyTVuVzw݀j> Lɳ%Ɵ14HW g>^LFaS_vUG˝U깛;uŪke) $!|}:P*ute^ɾj'K> ֤GNHqʜRwoSY4.<7]$ 7$:N"R1߁%" +%k6Dxai 0jԭlo:7ρC.Hߐ}e0@!\Tyֶ5'„&2INש8q>-iEǂv׈`ja?R endstream endobj 2236 0 obj << /Length 1191 /Filter /FlateDecode >> stream xڭWo6~_!*KJ$%mC֥CnEg/YUG*q~GRR$[qdgywwG[+ [~[~Z,-1(|BBkXvο/>wz#GE5'\AbsF@,p"+g߱O| k'|ꁜYQà`)8n{uQ؟՜`[a[Z84J`dn w!*Ӳ@x2f`9$D,$Xt hʌyY5+w#UuTh2 u%7DkKW2+c.<܎˯^}1K l8 RIT1[h?7v 8D圅 2c?auBgz+n{-J,Ci"9%Du4ؿvu1j!nD&yYJ1M3BH/;#Q);T6(jy|ϐ~? @L[CUVo"ٞ22:֕7?D\ `ped$_FdpE%/'c>r] .O |;^GUע2ӻ9a6xQ6r9RA[E(VZ ;3zL}{k:wTDr+94D$͇/J^#SV|J!5۪S֑=jS8ƺ$Bb^7dt;5[كQ)6Ҹ}Kb> Ry=]]L<Λ*"iԗa-3_Ve>pe(:Peb>4x)k&S@7G8v(0M ݶ#IZ?9PćnnÂy_3.<ݐy=7ODυZг#n8?Xڪ=> stream xZM7WPdY$#ca7ڞ^ɐ4[Z)IE>_uHT).I 8pti`1<9aN.\_ n^ݺoQNj|u^.yثU *ƺ6#}2 EEJ&'W%\*f*e#b䝑z#QmWHQI'fu`'9NNj]m;ت0}-;~\]{5o'W~Pg:Ń3">a3pa!g4ihTF/ e)k)mLw!K1B>ih"Y"s1sZ!m.l٧*Af=LC>W/鿻4cSN&&䝐󘜇Xbmuܲ_YwuϮgw)C|Fc{T!|U7f5{7 Ŵ%Y04ZG:aqǙjnף#B:!l%D4Cat@ p l9ا ] S6); ?^->#*[Ϊ|*S!]F;DC)1X}w9unMp§^<ڗVK+l}f| ܄ЄiBjBnBٻ1F+h`V1 Y{,V$>':؈0Ce ACQs.ذv1+)2jFJ[C){@vB< R }àG Rx(p^ndys-Gc?azobDŽ(εk{/b#fw9<^{ Dy9Jj*=8|ޭK{-ۂ ƃo{hvcƛy^O0 SЮ.Tu'TIړ<<z9792'8|Xyjcڣ ,$2)gh})AWρ4 p{#b9;OV}+?mDt5zZ/]v4#I ׳'G {E% " endstream endobj 2257 0 obj << /Length 1218 /Filter /FlateDecode >> stream xڽWmo6_!f5KRDu؇ MY5NdXAINdі ;) I&y<co ly'gݸ1*>^__esL(k,׋f]1s g 0U3rfj.ȸLVJ[y뇩+@-eNՍ.#; <<>E>إO?;( }O }ѩoVe{RKVjC.$b ef=24iN^ wvu>]i+6A nN9dQ0_t=YIlz^c.7mMVQJZVӪAA;w$8ډϦSpI ƼfkN&~qǖkλx%i_LݻA?Zfy뒟ZH#mϖ >q.KƑS֨֫UQ(xP|%NzyW#ʇ=Hk>gRYK-lO,}  E[*͹nlu@Wz|^guj`9]X`>Nu AY՛QćG-@x^k_(|rk:xm I]åue^Qp{ CpF޽3g{%ix"36 f>_ZY}:ީu9G> endstream endobj 2276 0 obj << /Length 1113 /Filter /FlateDecode >> stream xWKs6W`&P3xq:=iƭMB:. R"hJo_%h4e:p%}@23D >HQi=͇_?\6/L4>dC¢1 ۠$%nEH%R EWb3+%⠅>4]+qP%H [A孉7!Su GLUHWab?T< W!s@.b=.Ta_IGGb]wpnhD5zrR<@S{H3.Ԭ5~*%kUS /TIe.kn(X߽!ķ4Hc`My^vcqޒ8x;pڱa9('>l( ݪ]ۗ}q#$xh0qV|/9Lt"UI'k4>!OgV[I&*:0D~`nV kNOFH]aa*y F'0j/z 0*LfOC*$aUА}SzGcA0|qUWN2 ~cxz7Lx}X0k*Xϋl؞gY3:#UU˾Tx#ML]Ia(;Apa`0Yċe(W˄)+Hװu> &o kf4޹y]i]dn` Ǜg\`3䍸/@$wVSc5ocbz[E%[rzlF^ q@> stream xڭn6}( T"HQvtNN[ SEj+ͤ_sxHݢx9<`u V_Ջp,jABYfbuݩvSVo^dYRs E`ɼ|-sDExo+E#%m07-}sTvrI 9\:%IȄ%b(FU+ rjiTwy@羭4wP U؍-} /8 Xi 6&pv/VU1c4sdͧm؞nF[5umR,,>P) V jC>/Y ĴZ]åx,`gq<0rG# v4qd 7mk/(V!/2:}R5ݢ5 <gjr֚$:jzO%Y7hΩ?\z+'M4.g޶mT=NѺ3q["b-ҴӞyV+6ϗfu-QqhcC=U4~]-8\Ȳ ٺz8="-9 [i7nZPuɵn׸az$%?LqRu2e_:8Uۗb\ؔiNuWJ?4OyN +E( Bgvis򞸒?Bo ZKIdnһ:5FaOy]ܾT؅t%TkRvLd;&\NPlŅ0"TN'to3&@nf8&SsIg<568PD5\L_c*uBw\swS&aN bpTieW*@r^n 3͢l @Ak?JcͱIWBzy!/!Gǩ09:;"1ejLq8 g n(h"t)lm-!èGQB@8z&U"U'@X!C2?8xMz)XZ. 7XY,Q5CG H`:ѣ yf;Bw bG6ze}AAJ(d sV5)n<#klt+eUpV;vzaBԴY3AdB]Q=_!g}fΨz4uIBts<ȁlu?Il6\F8I.sFniD:rz,o:y2J]:@զD c>2m4}iK@PcyX𔴽`w0*dmP'zvC@Axm.`C>N߬zSeY?Ny~,Kz?&C$-*ٿԕE=bzRp2c D:N{YĂ.?e *<)3px:txa Jͱf8XgRNǺoϧg"S~# `A( s}h_ۣ2~0 ZœxP4'mRr7ѹ$azgK4o7Zu'(=z'{Wr endstream endobj 2310 0 obj << /Length 687 /Filter /FlateDecode >> stream xV]o0}ϯ@"Kڇ{d%MS{nbgK Qd9sL9"h?z;G!JB!M)Vܠ?Oԋѻ=ErCqBi0'.Q @:L!QWi1˭EZ@ +Ѥ \`6\[>Dv0N)~P &cXkԳfl( *F6Xke77U>g"Ⱦ">h~ `:;y".΅^%/U!_m/zAL_Vhw}(\ETDOGsZ ݡ}+_PIѺİIh} *27=)y:qZks~X?4FaBrǺl>Ur:ݷO=jmS=tjV0#A#ذY^N.w;ql͏W_0l=mVehr̟=ޝ`7uhb*д1H|Uu?ܫmv-z0ZsAy0E'IrG #a`/ ΤdNjlw6y6 TM1ʡ]0aroʟu? endstream endobj 2334 0 obj << /Length 860 /Filter /FlateDecode >> stream xڽVKo@Wҋ-;jn^RTmmDMkp ƎI3}\qÞ4 JA.*X*O饳&ŮyGzxle[̅o\ WJ\-|^ 87Dh;/dMP]{PlҮWsdEJL8nNj9K lVZll̯cðs,8\L*n a~^eZLYN_{{D%.n O'Sqt XWpc4}ߛbD'0uEܱw׭3 Z6xfpȏKeOUFs| ^⮌Q{JU̢dnfAe7s3)gڢC /62eKvm p\6j}GHyTχ@jc~PjIb`>|;Ptj[*I38iv!r!xnVڒhE##"jίX "Pg`yDa_v?ޡ6ؑ.;epZj\Iˁ6 MKK_`v6' endstream endobj 2242 0 obj << /Type /ObjStm /N 100 /First 976 /Length 2159 /Filter /FlateDecode >> stream xZao_- PCr\r@[;@e{QOIr}Crtun@Ro>CLN &фT#HB1_!a" >E*sB*`$!d(!]1v/׶P&I0>fh/9A,'Y\1N P-B?-(Q[d%8I\矒 1`^1A ڟ3*tٛ cbv3&GthP#bTy#;jE"v/ CS҅u)Rnc1wh.EWj{`⤫1c.ȥ%I8|M1((&qQscSU3b ac]*C1׶\E%Vd SR;6ԴX:H+NRFZt]w  LVX*`KE%R MS 0BE=0t)T[`'x &Շ=1Ё8+מ`HlTN<9}gFfdrU_Nf?/ŹÞwoGqUw21X);1_`Y 'O~fnF7~de-k~=lD )%R' ُr=Ԝp!^_w#bbOsfv;ݫLU픣|m,vJOmF1ōb ~OavME,lU"(Z7{`\|}zsqz :-W;807Ǖysgv'VK Y۫k-緋ndޘHÈhTS6'/1phfMHMM(M ߄uoD+= ':[4W`]Ta K"&lf/fj81!9ɄRBtُþOp9o Z/Ьax^Mpb)`b V0}O'ד2Sʊ)Y3$ڋ|%fאx(Hb!# E-1lXI`{`o; x+ M[0c=.\S;vB@&~iRl}gښbl&|v ''/g>O |Rc>1ԘOn'7Ƀ2d3X#2և%[EUwϝNn^u׷WFC j hQ;4Gq5q4 Qz;HBz'=ВNM@yƫـ!S@jpC6'ozu%]35<E0 c5Н6x=`+DGVOQN6iOI4>)OJz2ؚ1b-E~8z.RX#Dd2݈̯~7KXtqkmoʟl99>VogPkOC:heC%&BG}ORslȒCE:0t C}( /v9!!+jSAI=Ǒ/QKãl1k$Maj3\~^KmjlRFfS=y;oo/7H.ӟ mԄ܄҄M1xD_  YO~?^Mӳ_KY] J_8^8?̧sMnջ$ endstream endobj 2347 0 obj << /Length 1146 /Filter /FlateDecode >> stream xWM6Wȡ61]4H֦wʒ+HdQ8i"ADϼy||C>ťdFZRW1.$f͋˨?1.Ob2\!__&%z=1!0rH"UXOn>` / =6Sg0Nɇ.y$B# nB8dtG@bU 5^'׈*qNvaH¦0H6Ug^%u*BRC*t. r5$WetAn!Fi7^!!EJ!2?-d_~ϞB٫ 4E+OR5|gx8Ҋ29R SfiVն0-ŋ[Rǀ!eH{eyR[S$+[#`Hw?oߞ ޕKOQ&YaƈF0?Җz27WŌvmJ6ҎT=:~M?gDLWeڔ>k&m!.TN^C!$'Y mZ iCm4ITqGN }wiD_B-rW @ޅz!1S}ݗ_SE1Ò M\ؙ>|N&uJ8ݣ:n Gr{"ŘvcqTgCN]#E8Rs982K7!o@q/NS endstream endobj 2382 0 obj << /Length 1022 /Filter /FlateDecode >> stream xڵW[o6}U$d[Sh;lvb3D9M>H*_!M+w9:VM~M^_Ii#y`25&ejoC+zyv#?YlScE[_VDBm=*32.|Dc?LQ/xƾiBS)doȓI$m]#|)r4(R)OEZu8(9CRQ|!H 1|ⷳɿR%; MS[d7-!-^m<Y$wMt.:B#F'pB#e0EZ(k~rQmENi*`ߍ]m%!ػɭ4ߙrMGoo۶\dS΁`Z>s^ uAڞ}RK|dWm2?}Fի SVT7yQ/vҨi@rG-{<)_R0+>x.nE@:Qv?jotI>r"L"hK[sg#Ӵag*d H (A/EF19+#S| -uvi?/ZbeNOALCLcikmjë`֘+0޳:[m3<2ـ endstream endobj 2395 0 obj << /Length 1214 /Filter /FlateDecode >> stream xڽW[6~`&g" N$iuɃ ֈ-–Żd:;w.` NwzPz%ˆ(,E"I|?l'kC(c&ܪE3|@;3 Ē9-))nAvmqI>(dJ٫Q*yMdj9TRQԥކ JvӔ.EvdZ7[e\5ǔ*wN]NYo:>H(~VM殮߰R.YY\qx#*)1qtpB1,hRն;2 "q@j4BD#t#n$AT;o?T֜mDo窫.Y\* ~5D! >_j>IQ_Z %W%дa:$,)bbvg_|!&vf܄I_+E[#I q"Pd|t_7F6JaOSa)ccm J!=7kB^Ā49tѧ` ȳS0Sp4&0c,|]1zL@ 魆PkPn~ZNm{%%هe> stream xWM6W!fH⡇M4hvrIrPlZVkKhCEYXz082#iדɋk )AEXc1HBTXo rϋ7/E c1C&حpN8 s!9bXgM]*Cw%ɻ߰mwX#H xtwSaқGa"xMRgEE/pF9n];+ָ̋z!cQ.Y #DĆevSgEs6ۅJf,&iմ0tq,ֶ*vnm˽hG`Yx$DaĤ:{7F~6 q1!&Y^p IG S>B e wQliWc)=Qt7 >Ѕ?R NwUbn`)"yd {[f=@]p}o!YdbJ_?4gDϛ'4@ S@=xa ڧ~ O28HT^ZeK* 4u H.S8(ڼ{/ua"ćeTaHIߋZ?felo2̺ɗmʘ&+uuud[aۙ>-9"WZB",6]poS 'ۼZLT endstream endobj 2342 0 obj << /Type /ObjStm /N 100 /First 976 /Length 2103 /Filter /FlateDecode >> stream xZmo7_-%7IIўuJ {u$n#!/ CAh(2L$aaZ=~O85/bDR$4ƑVd?Qhe3sC |cu<*&+X>QrC@Ebi;DA$:i -y߁E)^piys7C,&S25sImx_l U N$kcDϨZKjèppK!KZ^U%,/ha#q6Pg>'y.1pB,k2$ $lh@aok'Xve>q*PCYC2|n)PM*S07:KZDp~-/Ml; `)ǑB,&N'$\OH.A"*mF4( (bwLPl*Ny̟T,)R[rqLxG`<"Xjl^c 2\XnL>98ssp6\e\hT<{wUx6lrǏףϫſGŃsⴜn9QP5$('y-`;GG8ճJ7VA|RN[q?_ʨ(u;Xʈֲ\V> 9Tl'բn`lZ`.@K(mWa_UҳWj.'l`J_4$9cjXˌ}b]Ilgn#uFܕo 늄 ١#@'jS͒dB iB3@OjzV–D(o7m|:(Gl Ysp]mi\3'WoE6\<S|:j8B:=mpXXFHl]H8穸D8$_*b R=rn@X|w0ܖVCnC.QYtd1]/&BkOnE}q ӗEFl"7Å-vW-цO-aZ]Kh%Vo%Vrh%Vrh%Vrh%Vrh%VrHƽ,l>hs!s+5m9Ѕgװv]a V,o"8FQ|X__F$O0>|a18)u?m[O6T!I˘[Ny2d0&IBX5eLxz=y# خK7`D e%"Iiy%;ھE6MOq;@w1Í:ߑĥ_Wn(LGnOБP[FU ӯǭdx+*͠6 6\qrF] ~obX/ __Bx9K)(X14Ӂ `)֛Y8${sfk<-ZǮr;> stream xڵV[o0~ϯR6`zWNtU!NJ ä6 PfSJC|N"N{ }8L%[6G.[>y;8=q+-nabqا\3;9 X#Aw” ܜf>C7%h _#Stl8ߵ-m_{,v%qBwTދH=Z*֛f9s$sQ:Qcy^ LJiOva[ru8lj:a(MW{&;u^2/v<z6]n!8ccx,W7ǰ.f"Z@5w9U,4*&Lz>uM5xE}Sϴy;Yj2x':JbMZqS!mzFJO8 n%MHFED>4HvסkȂ7K&u7 fM1ak[^5Rb*QU]> stream xڵXKo8Wa-II#=xdEatHVWdERmGMP, E|fl5j|'AIխC0F~:!(*wzWT,2E8`D_az }xE+GM[º:a$A]x7kA@nnL S+cjq۔e#uVm\-?c%˧ 1`O()?4Dgk[VAC*kj57t/ |Jm-^p]m1eMT H"[0&B8 \t}JAwB-EPF+@$(;׾4sX Y|)!N/@5 0ZҒ#!1m]J薥:Ns{͙J$mJ9ջZ[ޔ4dnDz1IA6!J%=:wVT{2u&y ~(&!CQ9I~S, i& Hc?T%O`(t[)$J1)DZBDTR"E4~^YNڶ~7͟=b@Y4Rokd> r Y;f.ax.[(ZF !vuPb>B#X=]My8츫bhZD}+n<_/'=K1JH2䥺 =X¸ XM=ER d'Ğ-V ﷬n"[r?J)=̣VpDﱡ,%p& rSe7 0EAd vrxЏKg3h[K0 !|İ8 ]Y=C9Uě7{pFtո~4IsJӆ!"SM̪b/jodBP}gQg'KB_ms&G~N4R R%+0 ?Q^3*n;1ü l%{W p5xP喀;Cɢ%TO9ntheDӴ9kmlִN7e}ɂ~Ahj}+[\d%d >t   :b aqYtR҂طWzECΨ~U?轇}|ճ\@ohhnhrxaE{]=1C3Say{ Z^0Fͨ /Fn9KdUDhFT3=I|ok= ]?cW endstream endobj 2462 0 obj << /Length 958 /Filter /FlateDecode >> stream xڽW[F~@CA aR_m/fݾ8 ì @Ŏ/Rlp9|;;,?H *C0F$@;Yyc@ vZDu#yMG~S 7;3Q(ʿ%6 _*ϧxO&w 4O򍽮=DE-rם`>ubo,QlTaDfEPZJ|0]wiU̢#ͥ=~nQlJ J[55LƦ-B}5HP9Oc~:0}_;Wa:A3I3.fifan{0ҮFJSv|4;)v fG- l{Ux&(5]nvYjcMݽtzn >۶ptv Y_ TCʦcByFX_qcIX yTR3~\͛ݟa'k_,kY9a|v- endstream endobj 2478 0 obj << /Length 755 /Filter /FlateDecode >> stream xڵVMs0Wh4$Ku! m0CDqC_lɱ0w 1@y5w/(8`!S!/{-7һ__m0 Be&X}A`5EB*H{#j rP_p|Mrg$ K9(B¸7! ZIVajzUxyWQMyq%χsAD r`@x 3 ,f[m%*#  KÓ~ ޸XV ..gPE.*5cϊ@TfUy4\qܚYjaЂ6O?yQQy[~ͯ#B./H^-}I6ZZ[묵{+('ϔO&)5XB,OS(&ruTDJFeVy, zTk#o@Qe'R6~BZމ:(;{{'5:Jde+Bxھ`aNvgI:%A30Ԉĸ`yKDJ;^Hu$_Oں kI])퍸^6рPw<U/.XS1>0E #ҒFdq =][ px+\°YHߟN f@BDecDxPvL@JCYRHoL=pT?V:` endstream endobj 2493 0 obj << /Length 742 /Filter /FlateDecode >> stream xڭV]o0}Wm4\?!ISTii=tD7$l~l($$ZLsϹ6A+D';XK&QBp%Rbh4_ۑKն b4J$ϣyi_Lf`/D66]c%(gɫCS96Vn Nl -ÂO jMrEì2?2\aˣ ڀ*BQhxw-OH]e +w/G1:0:eKN /vE3:f}&(:u{!J:µyʢѦ)`8P64bB` ybӬXB?|zn_@2FdbCB( hN[Z:N.Tjv>Mvk1s=@9t;L1%SbzpNId3`'=X0BIH|RA7׼֫uVϊ> stream xWQo0~ϯԇqm -A&SA>-d(!abhRA"OdT4U^w)wx?|P qr f掠&L/&.s@Sm-0D@ "=~:w[6=Za1ZÑ͉5u!1 ua/9aƉT,Z*m: _<} @p|bRX)#FR+a4ܚLZY^x8rjTF&櫬riL4J#Y>Dh'a6P &#RZ4Mc#~n 'ƅbaaV:80+Md\FFŁ*  s7fII c=vlXE]fF1̸&}T2t[>?ɫXyOC 0)8J.erNwr!r V/8˿OWrXOtl a0ĺ(lqDJAd mYwWoWƉtmhrYp2i1i%NnnC*ij4C]s5ne~&q0+ m\u0سt endstream endobj 2424 0 obj << /Type /ObjStm /N 100 /First 965 /Length 1738 /Filter /FlateDecode >> stream xYMo7W~F'-)AY2r,KXj>3!e5(-)iU&($=^ʔ.mT$@Ҽ 3EsFfI*3NbaA(P*VPf#:d%'ڽ1#`hod*M.JTƊRXNo6,BE *^4W)aN M|21vXJ6QFHN1pB HJ!L๙]P,&8/N F ~ˡ0cX8a9,c؅S[gtec嬂1D0,@x+͊B8*0I z'CCCBt! +!$Ӗđ 2(THMoo׼UڌX>To1Z O WIիÕ"AL38 :vsrZ |`XZYT6>P޼NGL|h?r_.[|蟷 8Y'#I^svɤܞ 'ձ` O[n'v<ςްkNgSy=Ӣܜ4?67T^3qr5âs_3`ŔGaa?>r|҇W#=whԞ=K^7rr.r6x?->5]搵P%TFTh< ɠId ;Ac;j>DX oh#ڻoh?S*Q(Z2QԨ(s(/1,CI^̆qszN}.M]]^N3My;\ L.n8>/hiu?wkH6}z~ds0(JdPvPbMy}z;8lϮ>9/HfJwvQVm@J Kb-$3Y~g^ƒ}I%cĂe͖֠?VO,GJF+|4:MQj֒x3mv濜mc^Ya5*NuX-ó~QFAG9InDq9ikI φ/e 7PJ:8&b+YT+8m 22m$s6õis&m|條qg|u]Xzy_8#TbDTî @d߭Xv9Vko \ԡ) n!>n!.KtJY.5q"(>Y(ٯDvrn}$:9H`Q<&>Z#:]s 1jmCD:> stream xڭVn0+"E+&)P j$A@KB+pү/79*v@y3_FK` um%gF@C h|?*[#˪#`<yvѼS}qV߫'^I6&:.&|ؑTOAi.aMZliٰGsyo s)훾 2Y`. c(IOoum],FGx!wEzDXl * 8.G>Uu DiVa Q,b #.#j&oewoG;$w膂 4$92YI mDz̊lWʷfu ]dc[~C/X撈)iv/3OS&y}?njh ߴC{" I]&eU<;Qe6 v>r9<(?M:}/N ͧs^$^&hkENeޑA-ܫ^25Um"^4Ys#b4{c&Z|jɽܼj=Q\Tb⦡n:祹]74q\t~DMDW?OUOqZp06! A3B endstream endobj 2536 0 obj << /Length 1599 /Filter /FlateDecode >> stream xڥXMs6Wp|f,AHI:θi*˽$9$H8 av2R.޾}0~xDS6{![m<WPr]?޾x&(Y%2Í-K{s[`5ԏrVvp\D .ڥe^4~l>.+ewq]_ƯWfÑ'aCRxOfcJxϼٟ'>}%qF_hu9w(Tv &JX7"9lQEߜHƴ(?%i>Aƭؽ͠-Rcxfm#6{EUUc-9%z C!M4UT Ü@BL`a3Yڏa/> stream xVn6+wc1GD="3IZ AAiRm+#K.E灢ˇdQqO6 /xEqGv:}}'AIl`E~:(g9c؜>G}QHO0+T\fvhܟ6^vOp&Q É /(É^IPTˀR;]XGI@VeyUIe'5N삨o:n\yWs[Л=.__>o~ vZޱ)y֗2XgQA%:WRJBa's0l۴WF^8ʕ= ϣ..񐀴{Pt]AWεQwv Fd^YUHz~Jn+zjV.)fd+5&|AM'ad*W?$]~r}6`V_?$$fm7 +]S,?(Gpê;} nV$dH,4PX= K^m7y@D}8Vb?<;eD*T endstream endobj 2571 0 obj << /Length 921 /Filter /FlateDecode >> stream xVMs6W`C'Li}R}HئCIΡKvLCbtz7yNNGk$ %s!KQlaN?ͺX{qUU\ws-r(MЄrBh=. DSwM}~gm434Oh~S> stream xVn6}W؇@P([!$-8>hmV ]6w$RJ%)ڢ e3g̜!V_:g͖1g<ʭz8L~[);7=&Hވb.V\g¦6lÏTZzfj3'T>!^\0"; ͫxt;s#Y#J 3&w"Y3fxw)@I|E>f˩,PĝO\ıNǏ՟C6#l* 2&F\O4_#1FCBLN)RPEnGX̼V8GQE'w4[DR}~m8Yq> stream xXYoF~ׯ pH$p-?%AAQ+E*<ȏEJ[ h DKrvfvof{K{oGNG/DKPЛ.<1bAE%t}7_vE12}M%!*b$a#Y+Fif{Sf-(CPK7n6^߾v!!z1v%Jiҫy^R~Oq_M7nQ=TX&_VOz7B*"(!Ea<pWr\TODU>OJ)PJEaCՊ e)ĚhytפqSYdw! 8c g QHM]2]KPřY2viQcKPYa J-6oW4zY+!S7eW-[Ip\dC!er(vTyU ?{L4~;:F|Su!y,8։hq%QhŦr5wi_OOQ/B9h$41xv1;{ST8[7VMM'1%d g}2P#M N7-رʬͫRRUYΞx {q*^ #G܁{us,Yjj:w$ f)Eݚ f0ʖ*CHU>ٙo~\i^-ZGzS,d=ԟ]SLǛBUZ)8rhOY糧|YJ&~f\s8*&%P5XLkPu;ntaIH v*$ލBҖ 15ɹk:#!K=Bj *ɀx@vD)UJ~Q`!..f-4]1ZGc&y WWre'Uy֎TK`G^J L$ EF'~u'\l/3 ĦF}U4JR?+ 7::0'X;^q"5:  Cy0*YWuĝsoD]4~$^OG_GDq%"T`pl={s2h)t # f#/.0 0IG͡r60L7\{\-QB ) O0:LJo|Ӛz{vBPU [!a- ;{IK[=v@q(`zۤKqDOn|J]HLJ>YNɚ endstream endobj 2525 0 obj << /Type /ObjStm /N 100 /First 974 /Length 2213 /Filter /FlateDecode >> stream xZMsWhAndv$oUJKiRER^5ġ%Kޤrpg<458}1%)B1 Ѱ ބX SŲa;M$cN$aɥc֢MP!KΠ\!:c@A*:S%deP:"Y%,QaB:Cvu>l$&|ڨ "C*NhB(Ī % R2,S=W U"ЈRҥ@{d8F9GaP<$@đAy0 .+a=TYStjDT)egp :vS6#pP1:% @¯t)2փaBTHЯ,)^tDN%{UTzIyYbúF2)cEH9ƲS~-d#h뺰jUb#"<91d`R%L B»DJ() flgU4eaM 2D;{{;_ep4&y;>'\fM.'m}ܞ?L>CJ)nL1Z\_Wxm7OSU@V=ޭs-%ZDsRi.[}C{VuMb 5r, _1cwy}i80Ӻ{yuHA`ޱuAջ!9˪uvbp0ߏA{9̟¶Cx+PzeuB,Q\x0kwwgOсo$þX:LV0XD8[Pl*DF50 習*:zB\Ã]?Ddl h#S_4 D$D1PXn:`=ΝE۝E; nuty:uqZ^‘WCCHE$ow˻Xbroм<'uG|>6t0ɿLϚ(;;<˫ f1{q6%Zyv Lv8H|`|:jgg`ttt9>?|>B~ti2<=r<0r}'wv׿=_)0B"2_RV)YSʹ9-mƾ_NOPR[j0OF p9bt>#ֲwjMb7lfS3WnLm3%K<'xe@KO)ev|'NNpMk%°G9mp++,(V[t>45p*g~w>7"2xK{B!MdD鿣+ip C 3A|Y"ڼY#rɖ_&ҤRyMum8Mz_i`z[=­kcʡ=?])cw^:=+ra Z#e ZWV/?~k~^,qdQ2cXrk!cY{`k·ohu5i=]gAlyYZ{֤Ti⿴{l(bBzwUsCrO4gWA/ h'z4܎sicCm endstream endobj 2632 0 obj << /Length 1530 /Filter /FlateDecode >> stream xn6_!`(`+^tK6tx{@[ARQ-Gqmyn={.*ڵj F4:X@%!$3x\Y PveW9DSS\uv]7Q>iM)XD g+SNnboT3 ʵRhROc#טO+VOz{)0)0EB*Dal$k#!ɢBl R?(hz\[ȓOh5E`N>&_'} </$LJ %VGwdSo8Of& `5QS;wQWЭb֕r@nI凅".8' 9z */)|+KfwcAsJf:O2Sӆ,ƊAӫKGӳ@̧Ng~vaz8 Jc͹Fۅqs܆v[4.V`yC5h A3OURxw100R<#<bse.x V./$8:eG[SJs`qEׅۺijkcR,5qFlq9Ii_>{L2 ٸcvޚ@ #>̦T45ܴЗBv3W :{.\pI LY?tTM(I|+mq|ł$åܨaܵpeɉj\qe}u),LAxFㆽ3Kt։/7l긷(Uy"=&M?1 dNߟg 9o endstream endobj 2671 0 obj << /Length 1498 /Filter /FlateDecode >> stream xYK6WЃ >% %MA&͵UJ3$%YZy^ -qÙx{?e9{.d^##/$,ke\/Tq~mջOʢQ BoFV|ՂҐ-h/%ޔn[98a+|AӤmh^Y'0Xג,o5u-Bĉ#!U娍Io|Z=,`QǦfvݱgZ3ѐ,qU`iѨ" D*(CA6Aon~ )$4AUW`;ĥ^8ETk8a(?0x~`\J.)!\SU<@%A91PܪI@8;ka.o; $? : !pl8ƀ#  P̰ff5z`5W5lXť 3 sxH(@)&:+gpUoWuQʊ ;`$n9.fQiflW 'h"-Ƣ"dL3>>r!c3^qv߷*wvz=φS#|lNO;OȆg3Z[چ3`Hq9)F *NSSy=7xtHeNc82dk! I~# endstream endobj 2684 0 obj << /Length 1106 /Filter /FlateDecode >> stream xڵWn8}W HKⱱ1aۙF;I;PPvg1L*soٻZ rkƈ2n N\Yw6|m8Af"6i~gpDwKn+;TAQ]eYNUl/fܿMRaT&*72Y>nw?XE~fl7FNW[U]O |"]0ut4,LWB@_ð@ԇ3.UjT[NrsBvP4,ffOzr7@DVak/?TS35:ZA9x1 FCRo sq4v q)%HnxPk/R׭Jk_?1sOA@P͹{l ]RGEi.tX'n*p |әA}(n~k{#% U:j~Gտy3w<3-yZf8˪m7 F=/~1SKlN W qشjג4a b08lU&R8~c;t9Ŷ_O:D: t>Œ:|nư2gTӋ=y=tRU9Pos0D'iE!'xۑn// -rUѣ'w~ISG@<(Nc#`'ubTqMkM-){&(㖝5{Ym eI=NNe]=EJ+}f,Ti?(,?RCגc}g5V.E8==Qj ^}280 EqI.im靶9<_}_{K}f ])\AEѵ<,Դz]*n97\ƪHʇlZY`wweج:jW'W~_fI޻C6/Hؐk.Ujߖ6boLfmjt6a8ɻ#Go endstream endobj 2700 0 obj << /Length 1490 /Filter /FlateDecode >> stream xX[o6~%)%[סaMYHU\RJ^$Ka{k{/X<}^#^B̻(K|ےW/|-J-.^>}OY, fZ`wpwг4bh̨ϫNLDLTM(c{l5Tr$/*՟!Eyb$F8ߞ }z+`c$ aQ2P,w&޴и7컙$)J:qDf>˛Rb&N iTk{@ zȭK1MN-raP Ra6Kc D&l;[!KXfkgF I b4jC'd' =%&(` |JWMfsaўpPOV%`Cj;K:>\[WDérI#+XJd@,oJ)W~@dQu-ЙzkC)+ ca">8@њȅ(BW=NbS:KFFA%) 7\Bڥ?ovfUZ2|e),;{B%̮Št^6|sqtF]^pU5:}uv.`]]wnokJ9"(̄+ aN %`ff}qHKς߮܈7_(BCQ2Q s8 gYx(맯NO0'PQ$cI8-\N\ҡ?E,QU55P>E298(ܣk'mMUNߦ\gu7].C~$6ૃЃס`- Mqy7ul-=Zx hfds`= ˤe"n9iI{i:෢NOp(#snet-=>* {C0xo tagׁoNBEO') endstream endobj 2622 0 obj << /Type /ObjStm /N 100 /First 982 /Length 2259 /Filter /FlateDecode >> stream xZmo_- P|8$#IvM5$9 %*vYbjÇCrr]0Q傷:W.'Xq"!Nr&WbG#HN=C QbGH-oɰ"Zb16Aʥ$HBR/L{"( <H\ b Jۤ|0}PV>Xf| x^ o2b8"aT^PEE)I2.. Vqb78,[#/#RD?/]zI.Ѐ-l1 B͈!K0&x(2T&%&hA𹴈*b>b(/x9ʪ|$k^*9̑h$_|%r4Hь++1'Y~AD F`e$6,F2F3a)&#&2A 8AdLNec,.*^B'<,hI4h^)bl)C &#Ҁ!LGd@IO'Ƹ"J,JkDČ:ٛ`F|9VcF`90c7feymԾv4i]nWT:~oڏ+vW_[h޷3`h童~4>i]aU;6uթqoQ@k(E|:L 6W!T!V!?0kUy~9<-& 1o?;A_`؈o+2(Q)XRl6Bik5{өɻ^̚o'*Q:2em<%,# ǝО./KDA˾9ix 18jKaONpH(g QgJ&19cC&W9nV̀nIM`mD]s3[ >h㝳y̐9;M'O6?Zדf!?ή ֿy͇U7iLߕwIAl)}_凿|9H~[Ur~t |D[^LWÇ X ys.D?PDHDUx&@iQ03q/ Gjr;,oΗjp$.A*RF@DuT%xO)Z{&M=.o0ImL:Pޗ"9Tx!fpG9mL5;`{ &g0YcF >ceJeWPj^\a؛b]]v吩i#_]%Nb^| mp|m ޸9866u >Ж@>L8H endstream endobj 2726 0 obj << /Length 898 /Filter /FlateDecode >> stream xWKS0Wxd mJH{XI:v%1&3ғ䵴IИ8|Omb0ll㙁 چ 3ƾq3Dݎ:cS^yYKo%MmRZmHv;BFiA8&jTz|'j2 4x:tDa.,f"]1AYZyƳBOhxOLs5{KIIyVx9}`.ny (_H3"^o2qƍ5lWdpyn-Rr*Ow#d ߃(HN&r"݊JK!5l5m4`UGv>| )48yRyy n }8(pP+6ֽ#([LE"硦mex;lOm"0!ե0f0%V22Ekp7ˠ \Igl:c8)9&\tHΩB##bTʽ锯25#v3%1F1RQB-z<ք]mIĭgdkTO2B;9FA;?+8xԓ5:<*`cpEco|+'Iۮ]]'@`ՆD6f!9i<qxD endstream endobj 2742 0 obj << /Length 1754 /Filter /FlateDecode >> stream xYMs6W(D0 4iII22N-6[tIʩ @@ttDRݷK<ϳ󋀍4ҒfD0FQ@LfUxMWQq.ٯ_% Cg ;||J~n)GQJ)#x<&S*8tE.2q-M@QEiؽLQO?LWr?y4T!hJ4ضǩGLoX %T@S|Ac[ p}(]i(pFI GY/yI*e.q>%MݭDnCrۇ3|Jl'_i̪B$0QM~LeHg,*Y{gaR<ڳ'Z0oxӭ,zaW.эA䊻sPm#8*"4}W+nM$+]B/P߁@ʣ=zQ].%P:ɖqW"^bB|*>u*dv{57z/cH5[/3jD͌O#( Wѫh.8)#"T&V?6>o^aXnkFW^(# ϓ.D .eĽR _Ő"".Z*M3j$┝ CLSTB!CeZ'V7+8Rhm]w8fMYVSgpY86@(\?y'{U>٩@op4=uc셖y~Ef{tsZ#̎9@gR Οfh893C TE {s]=*f1)3cلqj&F,D+(76bsث Ӥ7)/ aHcM@ 8xtݽ<1{̉p|hL^CG [zYS'av H v *oH6.w_LUJᦻ] -r) |s;l|9r@ƐPG|yhEl9O!Fj4L0-cD'Y w{fftJ̤|ij|\>Gǹvu0Ǹ1}7b1ǮpxPJUm^r\5ꪾ_` endstream endobj 2764 0 obj << /Length 1542 /Filter /FlateDecode >> stream xڭXY6~@Љ"4lZ$y-V+(e!Yʮv,po{[{&-'nC%( i-71?"BPozn.) # DgQ539c!qiel7+O;׼|+F~7rܩw\|v眄(&=OZL-9 e< |Рٷ慥0D1lr4+aY ?QY*x(-E  +;+Vfd{mNX#U_m0-NP|f^%1Z4%5R5.q5!ڸz\xu@^n;>%Ȏ鴐BYzAN𰌿д:(} ( KzK;E;' 8S>8u7_d*P hDoUʜOaŷ:+g$RjLV  -<4]\)oc QŁWL "LZbs彯Ueg1-L3<34s"Hd46&jIxɁ(uxZFCv|y- qMQ!ab԰js(fa?zr[EQ~msB==7!uD1ޘH~17٥H^Jk 'r ٙk7;Hi՞W@l?*a k'Q(ct6g VC.Ƒ(R1qg,K]H}?ltίc/(c3g0½2So,Ӭo˅G!~S ?WN\]];WlF;2;郦]-򊣍N ! *<;r_R9;, .f:'gh//xԏ?o\+z !ژÇ!(CAZ֧P繣$]' +2L<'QC@L* @Su}j>Q'J/]GT,\#z)Xs;͢R땡NhB`My龂SڕBXٕK TIK }5Hw~-*ά&+plHTv'Z|VKqD "!ѰAsiI| PK>Mz B8`!$y+h cv H[1\xxʗ2ۄ}u-O>^ HĒ{0{pFso1s/ F!N˜\9W㘜 2pֲLW?A38EQfAI.@s9rwMGb)\tIQl`<]0;6&=7BO>Z=5 #뻎v=>pt $id^:ݘBvxs~4j:GpNl[ endstream endobj 2787 0 obj << /Length 1575 /Filter /FlateDecode >> stream xڽX[o6~E {ȶfhQlX-0EmRҼ"Ytdn!@H~=XDP\1b"B`Ip,ZtT^=3,(JhvBv v/K"ΛuU03!t>BJby^Gc Z@2D/;=KBaiII񲤋%ϕbuԮi'JVJki{ -QcWLx\^rcZI⺩ۢZ?OaeZ;WN.`=0Opޫ fZ)z\M ,jwp:%sdᘝ̣Œxre੒F c>Nh*FL v6J鎼MϦ`cD`kש Y}'$T]k Ԙ>AMWc ݯ\_mAP/r1|uTy w iSץN0Jp !/dndtD}eR'Yehyb2bx$vAB)`z8kdn|`;T&_Ɏ2bFeh auCD ޤSL|71qɴHM}Ro79,۔0g6̄P0md-u(A<+]ZZWjڴ&+;[zӁ` rŖ RtS_z]dPW>Z# yc,T"k^ەv uu]S7uWvf0x+ݢ.=dl\S_6өe Vz&#2lk6L SQǛWpR-T ё0s0`,rۈAhLL:~Eߦj*!(F|*S$!TM !{;A`޾~=DG@.=`9{˥#u\Nvz;ԏ6u'wztbk֒aĝkH~9~F]S)I4]퍝0irЉSxҞ8׽|1ȔDNfKF[~F$XE|!Y|lo\}w|KL 8J243ߠCqب(yבeVH٧B¡='3H;mOzl{|:g`%Dg_3y9x ȕX'Ca٬ЃG1O|Wݵ3#>pXHĂl3{9 Yf&ШQ.{_\+_!rD#(-DwBLt(^u+dAFNH"и{Y)nMI8&Jq_O,%-ivn= & 1 y:ucˍ=BO$sߵcy>s䪹qV͙f,Ugڙ頛ld;AL 4YRF: 2@b: endstream endobj 2814 0 obj << /Length 2136 /Filter /FlateDecode >> stream xڽY[~Zkr>fXEoScRE7? Z47} GRY)#p(b _& %}\lB-30fۮnu;EݤU^]K9Pl>bwq61 g|0\ĘVoXTx $춗, 1O* Aƀ b[LPv (f\M8>,jA/[Ì] I`B;C%M i8fnȳ.sRR:9 #bj8͌pʶvV/6`tjpAG h3˩Sx<6xf3O+*YSdRN1Js$إq.@H&"}+4<āMPx"h7 heγw*"|@ Y"KT Ii;@L&`e F0kQ67@jI|n_2#R맱Pv+ Ǵ(~.dYwc NN޷5NT%)jnYLueU5ۙ4 M)gqʛxy*}qxrXtV&es琈.[MD׼v;U7o^{2w.&V2@:9)0 _ɠS QB"LRKeإ2lSɔWu^DL w.meh*0H7il~E\N!kj%Rb2=;˺ ,( U{ 3u!m#@*q8 {F2-sSOam:ScDBQD)ʧE~.Ȋ+ {'Ew6$;8uk+;,9>m7vPmí 9"Ĺ .G;Ahzu1un m8 >=ql7o3* ĥ*|ޘ^>d[W]VT9Uht`xś=Dgm~1aB5'b\l,zc9S!}~16enlnmm9Ɓ58J!iȯde! `f Ss5t|G#La@_'4>Sl8Ez̿s{L:$m !INx%'/3ΥLJ̟nooz~q2psM 5y$U]_7PNڽ1?}9ۼC;40R$$? WZL Q)b.ɚּAaҗ>:Ao+DBc3^fY̊k1p2=X;TN+n+(S1@P*z^Vw aAANϦ=0VWPU'g[*r[Z{}|\C(C}7b(_Y#|*}?+uFgYɧb_鮳훠f]T]S3o/('48^=_7q ItpSW1 ȋ~%o{ϛqlP+,DN(ig*$zyEfqޖy)xJ>luaOeq$;((ǩXH5iSdWIl^_O\L=xod5 endstream endobj 2723 0 obj << /Type /ObjStm /N 100 /First 983 /Length 2510 /Filter /FlateDecode >> stream xZMsWhHicǕMeKV%|Ę8c Z-Mj͞Qט2Fr*[eE.%/BTU]trVQ.]Kʓ?`1CN([V!he@T Yr;I2 &$rˑ"#vVVS!E# (z)K$H=&&'<&ƉǬ `(e/Er 9"0H[eB1,{咕u0+\%͈MIyYyA@dG#xT!S$O^v񩌁i|vg ;Ζm%^U@t cSQ``axB2^*"%Vd$ҎP)_UȦp48A$ST6+#X`}a0X&]`^ 0T[Xb2L/&4/0@${ XL%R7r/C b-eKU٧(.E@%HU'$tI悘!8a-,!`Ď ,K͈E͎g'vrg<19k)k K ~MX5%t HN 7Bry%an.| o~uڹ:UϞuiFWQ鼗헙{{9}R% G#` O#SYs1ӌhc[k))ni!l1-޲mڪ޵7Y5ՖSJw&fkb暘&fC\\G2c$H`ߊdt9^4ЂGnD4:ĭ8N8Bfu~E/۾'Oɤź-ZuXu r~xDZKYRMK9y;U|r-\KW0B@ HH"Yَ޷t=:#-x}y՜P#9 Y_à%.M|@6Qq f CF~*}U ѐ,9+ hPWΑ\bK 6P(Z^Ʌwַ\y\V}=ǜԶha 򾰉Q\sӖu_O\C墡rXh\4V.+Ec墱TGNuU:Z@7shZrH"208;q 6HҩZi~{bLK`'e ðOh: 0ARk.0h㻉|0uFa=ɨ⁵3؇ M~{A8/-@7u(q4aY޼DžN ^@+gq #qhvf~~'taGوk(ܖP "Tʀwx޷V) o4.ZRT^Ӹ:8Sti_m'{umw"Dv7nW&T].Jr%y\Ieyg \PXT:2ՑÔ`}F\v) s^]x#oloDIyM4>hg5=Y'._h4}}%!_dV,o-pxÙ݌EG=et.9>:I"E~I oxb'i:2'e|MW/'/ߣCz݇Y'Uwrw5k~xXǏ$[-Z,&pI2 ͓v@M/'?{tUәc7> stream xVKs0Wh Q%KB3 :j&߳?'Mk%K";o!!Jf\R,B uD<{oήDSJ:RVlgr١ DK"347~)qp :J}OG:J _a }14NyXIq^I7i+dyi݉]P<2kwIjpirc=\`10ג4A.tU\xFD}*3{Gq0 )dTw3oYK7ku-􃎾ǰv1`vu>K&V6p !ZYfQQ4AY4얆{^UULaԧPМ0(V,xi(rA15unop“x,Dite-Xk$6a0w p 0e X]A0_}yT;y4{ǐ9VufH;͕,>ڰnЄc˼whcsvxJeZzxL]ڔ]+7E5]v[6!'8y endstream endobj 2849 0 obj << /Length 1264 /Filter /FlateDecode >> stream xW[o6~.Y +kҾ ˌB\QPdKQ0\sQ-c\P/B »p ʄ'1FFܛ1fwr(pQ}HʹЙڜȖD"g]OV.!( I'<qU}|JT(dQ-Dic[=%YuPe2w*d@FHFݮ/ ^B =Ty:i45+ͫ}MHEwj֥#`J'e:KOidm4u&jDe]U>SMWxڜPqrN4^BZ;&<.#z:$(T!".&q P~ލm^Drʖ*OFKG5^d QHir6lӶZM} 0ᾪnyNaM3"q$"8S%OW dIp tT'ٻٶ^ Ehh)Tc_bS]DƊ !ý1LwcX7{jm|m2$^ׁ7wn C}4P2cJ]~ݠK( T alxY978k7w ?6@GcRIu!YUixrj7⹕8 T\,aBԣ=ԋ<+luyH[k;]4ɕT~ Ҵzhpb' O{f;}WFre84C5Xԙ1dOf3Lzi<nNC+T'uoiLo5^aY²)M '#s$7Q> stream xWo6_A&5o"Kbur;"ɲ)?D9m>y}92(QB0 iJct9>s.zwU7 kceINiI4!ɿ [h4RkXM>w>}-IWH Zpاr_K-hkA V"%&TѢa6Н \3&IZ2)y +'8铔+Pl ƺEfQQghf>B &J]RtѓŋL\rl~f"bx'OmÈYQa0WFv}"|{UIj~EF6{у~㝳lJIܮ:w|F'۲ƶu([zaF`W!qnܳby,&0a63V%h~rheAfhs*FC^0"vMqmSaTgB@rl<FxeT0pkTgIЦ}M)\ˋ [돪PE؟=f~EfcOw0PqZuDoO0pX@b9khځc&=WɦB=A  6*}/ k]*R9B[_>2‚)7IS%r unhQ'bŔ/^p^tV}xmj<4tG»ev}&k DX#f2_@VvzՑj|uq:Y ez:~o^liUTpw&I ?va<Č&Y}vqbbTJ022p<505-Y 7:F7m]^dw4бiN0scšJzx2% ~v, a endstream endobj 2893 0 obj << /Length 1157 /Filter /FlateDecode >> stream xXKo6W@̐")R(zHMEbXTzdߡ()-Xag`OG9˵C0Fy yws3%ě.?_(ICP^@ UfA'.܎޼Q^R~nʭJR߿_1]tD"O;OKeZt2an?8>m~UX<1`l=wj`N\a, bDl6w9UPGħm56. c"H=[S:JSXfQ%1I ]C^Bh|V~$iBSpv̘v9?f; R̈Z_ b]:LU"e2$߈w,Par(Ck ژ u`mo qم- s 'ܳ` ܕ=ߜQ.9{|KeScA73j'\wmOr~j-[m)w( !*Nnn/: Z01vOGKy`1 tn@x-BLۧMYlw^6t \Ӧ=mc>WYhL<e( ''ط/yQM߸ݻٜc<]Ps5'r}5QZe@Yu-i&͑~4% {z2 Iۗ^pP3QX,g '()R^|ըEh1hXG{|MtfVP_nOڍw45dD*0g e tte5#|mWݪ~%!,lsfQpFJp{xIN*G|Zb`۬{}6!DoBmfZ{eN&ެ`:~Į|"h0R Ϛg!6B)>}^pFcF&Tk CPY!K.~iCX#?Chf-V^w:qa4(E;y//Gz} endstream endobj 2915 0 obj << /Length 1062 /Filter /FlateDecode >> stream xڭWnF}WhJ%h mp4hii-1 %37e)KJlQ̙9s2ՕbAFRL1b\$ `6lmaf$RNU CiڒWc%+ލ vTiPHim2{<i+^ƌd4;.J!!һ43yoyACDFDRzhm/*FUҟ

a\#* eE?b^¨Fܦ!Fu.jCEQ,0_Rhrx.w`<`AJod#ED!p=.f# Fq  \l}AeLβ4XJbn[*"͒0 \O|Bǟ^x` `s"$ `G뷛2H3zt+ZDAE γ9{%Ǜۉ=*6e(;Ş`pcB MMi1uGN]S ;|=m (|tn[+F*"3uh6Tkݩ,.vb5;ta@v͂[2O{,7DN2 8t qp;6 IN`=D!6VcEa'rqD1~` ^BqG*006WBm6Ojo ^bFxae߄=>4I&6œlͽl/Ɠܗz'gyI endstream endobj 2820 0 obj << /Type /ObjStm /N 100 /First 967 /Length 2177 /Filter /FlateDecode >> stream xZ]o[7}(Q$MpطZY2$9HJ8+ ;$狇}l񙊉_ e190WG(ǔT6k0 QF1j)FI{YIp̢6Majtcm G@xv-%N1+`DL_fwb$lRI%13IXLk1>W<)W#hSA^`J"Q(xGIɐPL@Ԏk"jq`(8UB.$-𵸤կpE2:8<<4^m̑"0 ͮw}6HniVЌ^!^CK{#(}@7/_l{eFfEw0:i\l2~Bh)c&xs_϶:exin*7ӠX~Cn/ھWhB6 -bK@O(6 i#mmF}XˠIs3n$ PHr ų8zZn-;ʭlގM]O]7BjBnB5z^*ћz2`|q-*~n?F/>Oa,*%##[+l!7f;mf_?8F-?T[VaԀX0/?C^bE! l{aأ&e땲mЀx`* /t\( -arX7Q>j@;('sp."fLb%^,~z;z01tB`@thvKt\ہEI`"`P>&A{S-Zy` `?aT>b ҄Ԅ܄ *@M^`nu ,XρO=6 !.W;[Bu5t ɼf/;q+X] > ގ|$ђ X0i'gmgB_ON. zvNjYl[ݷ3IɢXk|Pׯ, endstream endobj 2926 0 obj << /Length 1431 /Filter /FlateDecode >> stream xڽWK6W!6P3"%QTMR$HVzUȒG6p(Y ȡ'盱=un %RHowqgA(s&5jyxz5H ̥F.ʷ ^V_Vx(["gGՃ8 .q pɐ{2RL6 \G%jtWm"iq>p芺JKma6_/.5zcǸM O!c1,n>~״'O<߃K/Y 4XȢxl N;\M- SJ%gÄ*p-뎨w<>iZ'0q/~(R¸Ϡ{jl?jڏwn,- ;%GrQ !:š Iu>ڬ13MEwH0pLhx;'XYi6\*$$r G=p0Ja$; # s4PP{xfxLϨX_T%uZM2lpff6N1n^|@/kfF:Y\GݴR5ܰB$9ۢ/-&d2 @n "[`ST #uK>Ҳ!O`ؑLsٕ ,o]B¢sVtjLeuC %? />|#V Q#LZhM"5,~Q 0Wmଶ;!_XC}Ȣ5YJk d563T;+)ȦD嬮\UM}휆]vꀍsJ&!"o4Tc)n@N}0 ]R9^8f"DF!R.kP*ª F q9SkM-JCS6n|VQw {/RǼڭyR endstream endobj 2939 0 obj << /Length 809 /Filter /FlateDecode >> stream xڝUKo0+Ra16T!UHUj%"z7!;~k6lh|tj[XK B¾c/" Z,хY;g}v_s.f'IȋJqu h#*N$J9 İHS˺~_4`a3F.$Ԩ"`/sx踡g}ou18(ځ-ER|fɚ2eZ*W}?- pޝ0cL`;e2R)r+Wf GYƸ<3 #- 9}^W:PQko@`c/>[m>meuq%lBN$sGKDA~1%`U00 (FtN@_c6ǣdA KeX*Z},˲yWLlϊ v6kEcчJ$ &a͛.Q1vE7 @вFU@Q$mUYeJ Q D恼X]gpw~Wu;m^Տ,K/R{ 1'D &/vm CVIܠ`@(~Y{L*f0~9;I@{Z.>ܴuΉBӓդ`>t&I{H9x8{3eX%:('S9`A_C_MMﻓ@cGgMI߀z &nUNݤZ ?M="D~>CޚS*Y^qy˫LG0?a>[q%_fq_b)C endstream endobj 2948 0 obj << /Length 625 /Filter /FlateDecode >> stream xVMo@WCm㘪I*$*S(vm`(K=<7of ASDma\H 6I4|A̅DR,A z)#Fm_bNKRڲ4/ !At/hOMGF7w5G((! =!EPH& s=$ +CTN.FVϊbr.6gՎk/W$zoX7rL?j\n7jSh5}; Ә%ҩeϬkZ/3#Ig="WeDI8]vc,=PQ%_X/W݂.orD;l9\۬~m86MŪ4&6ڬ:&X;ԀL}s|om#WFqO8Zb񇆙' e~omu)n L(N 1,L86g\\֯Ǡ,曤;fgE~tne=@`1 6> stream xWK6Wɡ2PsEza Eݠ4@h^%GC҆qַ 9 /i$OĻx4H/$Qݕ{mUl_\\'S(OHp!UB\qu0 <: 3-6xgރy HYڻ]5x.06u$aK,s0jL5$yF/KjsX8 ;.%mN1J*7,%@;JBp4B_n˪mf=ͼHbPz+5d>gܯ^BZ[.qQAհ睬J9&J_ssxWԼ9 E.@/jAWW_צef6?_#LȂvO1^)„@ Pi9H8hB)1xJ5j #STz%n#wBnٌ܌HPdf#qNRAze8? Wxwsc6}'m DL߭:~9ɲVNiDs- QyO>cS=+?}hzbٸ RG/ZV(E\vKNx*UN,}2cԛ(hLBJg?.1}4cl͑#{vD=_+Gx&~"FO$MCMoZmKu:%$/!GS$]R(L Wxl)6K|Tn;{=JIR(6)"1Ih8pI'p;ui9J8kNgsTΠ$BeUp)P}4js#8<ZuTSyrW.(  =UŎ^;8}Эl_Au JoS>Y殦BQIhFBWo=t|+-b {Eza5y ZOf֮ljt }F芓Zl\mp,y|X 3LBn+fWmHϋl^ dNn,te9U&!W6Nc g%hSi 5ػkTO%&lBQOOO^ gK I;d~_ݰ3Rt"˧{@|L$E#6`VID|*ӆ,%l~/ CFZ/}lujz(ǛY0c<12O~)۝6?cz t7Jh,[ǚ'绚p endstream endobj 2986 0 obj << /Length 974 /Filter /FlateDecode >> stream xڝW]oJ}@CWm%6Z[۫ʍ-llr@w`&N];gfΙ`kia|B0+@š_[cĸr|$Butkwrk*I.*t&#È`=^*O̒b}V^}PG^2\MND?c*@3;jWp7]?T&əOHeeBT7w`InיK>#zZ/ڪ=[q!9f[|kBꢓN) ǘ"#`D,48 u9tMA pǔy9GV2:  `tz'.~CxSVxߩRY7EMr\rNqXϞi\2\#QͷDM|H^WĸU}8sA]/p4f2_V D;UQ Md&\m9"^fաQ>.wgJ2,U~6yZUF)Kg~:KG{&xM57}yr%q*#hc{ς7V02!ŧ{szWlI;@Te _s״_f\E_dzCuXD*b?ܾ|3Y]1V~mzx5TysJmI5 ʨ K66ΔM]pKGehna ]拕uKpZLϻ#)0 tPyp }#ȳlx/Fй㭣6mf0z3/{% ~ endstream endobj 3000 0 obj << /Length 1089 /Filter /FlateDecode >> stream xڽWmo6_!fKRDom E5އA3 Fbez$9MN"X0)x[ [&?&o/=RZZc0A[ fZ|׷>}PDl5ݣ[rzч۔2)~HXEjCM|$|~Ox'+yh?33v;}d&S~sj=)$iy-&8T!*3"U]M(5w=5_c^a %sמka"& FCkyw5 %+Ոvr8L;8ܝlɯvOeTg|*6l.νo]nd=7 v7W 07L*_A&˺z ΆWɹ1`u{T&IL?]-u-t!οT7r^}~פn zۄƙ^ؼ]~1qHVd)nt \!׭I۶滬*I1 jτ4GiN5"-KC A!',heFd/> stream xZn#7}Wq P$gd<$Xd@|}NQ-Vܲ[ b!yXƙP\1!eIo$IMfŸhrN*dSWB1Z%£x |B0>ځ x°xS2^ gT)CJ:Fr&̕J+ a,:+Fik\J )뺩NX8A/e*c *A_T5PVua9AtXE)D:\gXJn8CNi񐒎&ԩA[ cR*%[*C6T(r]pBcR*@J]K}O s<2$QevE#쩚ML?a}Cb^VRՉXTMIϬ:?tu8؊8ѮPxmvX<4Ώ={U@BB5#e U+l*URD*wشdKx[&1ѕ,rO&RFa(&ƺٙj(Q ~QL jA])$ Ť ]IKcٲp}?z7;ws_Ys4!:("يSK&1۔ ?3gqԞسpon0:.^4Jp/ Vwfz55ƿe=\ f2s}h?wZSYm#?vN%%Wnp߆tx,:'ĉ,N7"=I誙t^z-\٠XM>"٧wSO?bJCV^wcZ16bx;0☍-{(t tDۖhέWXtYTCr^Mݺ,VbuifTeߝ|ڵߚ^-5BK(eXxfT;Z^|?VRڛ6֨T`u4+[ɗh&g}n;6!f$vhI۱}6yveǓve)ՎlճE||lo),?IYjGZb;nF BGVFlr8>r8`9@VGAcw}-ђPȗ墴Dhf#.GAV9Eh% v쀐.=\ o\%cz)(OH~6%H.V) YcK[m&śF9^Ń?6έGBGIAz/-PK-8 ~UB3*ɏoiErХCO c02Fv@fyp9L5B"#I1k[p,bx!p@-(:M :dگ7FaCNeYxR1hCЌpGAXi[4%>Cׄۢx.ÓkF_hx#F!mZț7Amzf>]KڎyKoe+o( .WKn?{6MlaReÆ}[,wb1rw J_hX|#K8v Mߋ1R G3R䟤t~yL(rP$ҵ9Bن ;2{Ow|o'>tM&tGFy)>Mfe2^vME|s [\_,ljPz&@3YAO1GPI?POFZE6"Q4}_v] endstream endobj 3032 0 obj << /Length 1350 /Filter /FlateDecode >> stream xڽXKo6WKR(mC,vArE)#b$[_iiof8عsyt>w`<;{3٘P6~y)G=" TdU:;KnK h aŒF=:P $Z!8 xx!֬ǤX-ه FZ ckq䓮_6 ÝHPTy{ɫzuW4\U0^haPܽ>qI(=ev{/()r$NqdU<IXd`t EP Ͽa|5fcuiԐy`%s!F %(M͘`TdyxWRoz);y8{ƫuG'J>4;"\b{1gz,p;1l~X*c}t0n*ԹSJ[ [? F>#_p/*N+?Bˉe>T,՝0pA _Xh T(%P $V?͒3lWOf!t;l($E _a,R1lIbb c*s2ĝd.ՠ.FrGUh?S|nǜ Dxix.__y'0,rb*t hOG~ގg _X1 Mc CăE`\> stream xڭVmo0_a $ZėM/B!JPҌ$k$TUw{; rr~81`+0J Ic !5>,<(_dil׳q#AN+z; Am4ꎫOn^>]=˱JX*l(009g]>" plڝFxO*ۄ6%͑ x_QMthRM4*QNbvNUD)%p.G ɈR={fME :1:AXiQQ`\ W3f@sa08VmUYKe^^Xpn,R`˯IIϟ-B7QXj=b3A3 >5&:8=\pQ%[[6˭&-"B!`x2e@JzCpm0^? VIi-O?a(uK$wIv8Wi,l)4s1s8mQs Z>psGQ pQe$A~/NqU'j+ԑ⤬x9(C( piw|=&QD%ы eo7g} endstream endobj 3072 0 obj << /Length 1176 /Filter /FlateDecode >> stream xXnF}WHrAm ZP@+D\*QiF0 sffgO۱dFZRL1.EL;Й ۱]ʔ԰Qh:E#ko..&?LzoT3[ Giy̗3WK5đ E7/R}RJ M'.SC]YxIzۮkD)RЖHJYݥ&nڪkw<#o7i>°՝y.x+RDka)zP*Yfiwȷ&7o\O`> stream xVn:+tQR"Eh.-Ҡ7qƭ"ӶR=\INҿ/%Rj0 ̙3C"' vt0B!.`C`:8t4~< p!B\J2jwfꡣ7]<:yg|BjK*XAXY,m~yl6+XP}/MiXImȤ3c/_l2iE^X&ߵ:FPPJE fG2q E_AmDXBuv0~rwĆW&MF//}Vi:@ CnPD p(b RlNSu[.+Op#$D8x?U0*5Df7R+EUKj`@{Ԫ%uvPp\<1:9l(K9tXgS4TWZ qu)D6>تF6 ̃,\a-QD+QԻB/2ӔlUpYu]t]O˶ilaK/"~ z7N3L"͌E~kTw:K eMg_6oؓ i}urXXnգF !<$EDro@u2VQ+yLcFh3Df^{rKcMI19h#'GSwҙ.^>'+g#Mr"q3X} nL ɠߢ&ܡʠ%_UyI=v.TVyۊ`e"e̙{$wCLLBMןORYn> stream xZo[౽PCi lۅC[#VSHr ev-=/ϓ ?(&\ Iv1*_qQ#ZFrfDR4JjPpDE4 QQʍyJv2فNV;Ϊ8cs TI ,2;.xP/h^c5| B HNcp"K\h@=Bp! erԴAbhB q.%$8D 5ڷ3*m,ܨbnԥr8^5J }&`54'LX.``T!ဝ)lh@)b3ES'9QYSu9{7UL^_)&Ѧ#H%NcNNN%)VSSEU ]K37n\̪(ڰxfXXF Sb *0nV\ ]̍6s+QPsCP ]} ]lL Jq~dHݵlT2{"Rkb Gɛ7'Sw37_]Q~;jɝy,7fF=~Znݛ7n^ͻi{h,݃ {0q^]|Xlݹ|>.~ٺ}]0,ۍExv2;[lVf?..?~qAFpjO8he.+H;%`Q Np'b']2u%s]2w%s]2w%s;v͓ه_'Wź(|~ٻsj ؃HHQ+e`d!>VW/Oo|;w$˥E<$Yngյo74!e#Q|BCH?|DV:$Qt'=YT[4bա0wzXXGcR6Ʋ,6ӻsDq@J rbr4N#{4'A4Wh ][G$Df1=䃢jB-/99[\^Lfbg<ŴW(wDg8 ᇑS}>֫PBtWxR)*zRW/S.IEm4&@0Ay](QN20H1>ow|^ }aK6ߡJ0[A=9NFcY-sXPo$ W{`:A`(GH8{0-O2Jh""v %4\uͮf! eO W6r{<ݥC}U4Q9UCp0u~XͪhKEzGKe 9ٺ|aqo߭nn {-ޖ3bS03ǂ\f#EWUhtu}=_ lGvcRKhÌ}9 |ȶq#8iЅ!Cؑy|㯯6MزW%KS^AK-v#)x.q$n7d&gU[,5J8sܷϹWܫQ(j{5}\O| 㽰~n;iB~dFk~%|8't?4#4Z_~RMU`ہ4hS/@z?r~D?yTe3Z4ʩvfN CYuʃ} pt/ǭs l㏷Tȥ,;lЎ LFPGr[ZXѺْFrsʯM4ࣆqmaQma U|%y`?TkAT[{#z߽Q"adt|W$c!nip#0ysDi,w@~0戮9< A endstream endobj 3119 0 obj << /Length 1319 /Filter /FlateDecode >> stream xڽXQo8~ϯ@'m"ml0޶]imsN48-&m߀ &TUUxgb֗Kױ|Ե `Z!u|kZ1br=k:GRf6CQ]y!;&첩OA 5-MrEMkyᗺe!x<r<^ _gҎÄD^AZFh[`D‡G啅 ,7 N;08\TO*<A Qg)I+i>ULh.|b+^P)vqFωu pe(]]Sc ae)z}$QL$/?0K:|$H]NC3qOs8]hP=}%*{=6j 1RT|^Ɨq%á_'  BOdv+CEE Vq\ Qb:oDJ&R9p]kf Wu|a= 4koƲ41 gϽfE\*0&0ڲ";mw¬f[w}~bsW~ꆥ[-u۽!oPf4/Ӗ*o`i,:Vޛg+M?.Ͼ]].:l4v ৽̅UĄ4ْ>+TnQ_6_2a4j/Qׄ^e H[1eÑlniM3ֱy1֌Y*#Jnb"꿕(f1uҲE:c,QtHqk֑B:HIQ jBn2+}ϴwQ|~=T+:H t|p.Ǎ-Ow<| mg<SXϛ6fy r`|UcglxR{1;o gh+ggL/?jl`cr rMaVT#}Ӑ)HVTe.+-?I$|}gY0f3rJk`^̜ endstream endobj 3151 0 obj << /Length 1583 /Filter /FlateDecode >> stream xXMo8Wk"!M8B[ [N%9i}"%X"3o?'#I$9##p/"q&ܛStY\n&^(^W>J p>|Xb/@PoLo7<%X> +jOo vx@< "w 7IrfE>iq:7j_ jeجŰVI"A┢Pw*e}lRd։O, eԱN;'ͽ7f ﷫N%Ryׯ8% d?$lUo3BW+Cص3G>~n;ΓJs 7|;c>wl. d6Sg*/T%aY|[F5ܯ,],V3uWlI~VrPJPTKW}"drfnv4"H!6x:z?vիb&÷$ϓto-t$;!g{gs{3Q޿{s]|ʐ$uK5E+h/Rڅ+/d,u%銬TY6"Ў`i.zFāZ=;;Ix?{yoz +.Y@(Y(P>ke]})kCH7po/V:># cP}!\L;ڱKޔ U*aӧhR ժKK! I3)@n ]ߪM./ΰGk1\*|_Fέ:Aj~+K6Ε֠[K4T`nIJuzHPj򡯔 F ?u9@RU(WkO=]-F9#VB p٢U'n^K\K\sɡܬ,-wzRN)|k~&]9'1![^g0ሺ'q]o[Z \e<%_HHuJ.,UirXt f9=[=y{fWiTntP&8dfZkc ˦&ތ`>mZLy0ݰ9~}X@$ @vˆpr'+wE0}g|suX̥dXa@/ڻY-oXU]L"֤tTꇞA~:iJP4#]-џ^NqV)6WsTIOS~ -sQLJg>bXU''ŏr7Aۍg#2,D\PAXo]J wfçurwJZ %*v ED`g N1?|}qq4`b©Cp8exd?Nit }q8#&_jDqqJrp  -6WnO+?N endstream endobj 3165 0 obj << /Length 1041 /Filter /FlateDecode >> stream xVKo6WCbć( mExOmsW%yPdi.-| s<~rvsǩ,Le=:zsǘaڐC⡵=o~/#4{iXO25ߙlD"aҶԑ7{(-{)_<+7Yk4]k6(xqtHڪxʻʷEFcqʦR̛ja]PW:qv'*J#}kÇ۳W|NYVs V=(C[[Q յ(k]SI 4VUÞY6R=YUݥǔR#T:v9}j9 &B0 r<~~Z0vc,AQHk1W%RfzOC5~}phx9 +u_r Z^~=/h?/LO GaHt0D>gQ ?\0 endstream endobj 3201 0 obj << /Length 1210 /Filter /FlateDecode >> stream xX[o6~"Зl]Y^SmQ ۙ$ۿߡHْ,;PA}x.wHt2_ja9߸RF^/tڙ0 n ~9 8ڋ4.{w`6 +E6,~=xGnz {'Z hb h }1>D5?ZzMM3li捥ÈHhby"U&iG6)yi!k<.pc+~-p ci?zt D鶆YnLvhi^";Wa mQUZw}\#Gޮ6Nۤ;*?䫅ϕGO=_ZC endstream endobj 3095 0 obj << /Type /ObjStm /N 100 /First 996 /Length 2399 /Filter /FlateDecode >> stream xZmo_-z _\\ mD=[2$9Hh'(+߭+pϮfy#l gJ4H%I(&'9I)oOEE`<DNOg"*(b_)oHwd(y%` RD(@ɂ(aPt*RlQEpY$B0B*:>%ױTzu|P%(Nq(Eڔ*5z̜$a@s/{q2C|т(.P),d2J%'ʳ3L={},Ġzꘘbf6b1K"ֻ(>L:1W)[ ?@׵,]q:DRu: (8;֙Idc_`mrp&3,"BS!Q)iZh.gֹFj'b"JSr8]`X'0T)EbS/TSc,W _~(RWT0b\wPԗ)6Szu0X%W-hk*HMRvK5l]«}t||4y\l<Ü W5!?m?\/믏&߭/95>3ݻyu~&O[lֺq~49˛E7S}n6~|gNYH^a _Sbޅ)¶DnD ua[7FFFF4ɾIMo}d$^TU'u4yqs&,WnU^M2ɩ hoF*[9YXQ ^ɷ˗K3yjpړQt4 æ[`z4]z|ѱYwby7GckG.XMPԄ4w''n6"`5hDy0rjedkզQ Ct~_PGLr0aD$8\LCX4l&8 h !4}:¾lA4z5_lYtv|E#Nơp9TI_5ѡ{ uw ~PYs(p,Iq0.9T43ewjzfD}5?0^t7f2mk᜵OI6J:XT}l@U!k#:Ն[ckNізs"˜ D q/P4 9==f_,A8µW1=.LXȳL#"By P48Q!8=CQa5R=Hb Y0ś3r>;}[-zo+svvZne7}۽ZκGߏ Kwuv.u^I (n,rZK[IgDDHZhatgCtb(dr(K_2 1:d{͂>e[w2jKUP#S(w6Ƈ̷-jp#ppo'㖔`D(0%'G1L>݌g1Fg"ʧ~yg"&A1nt+- }5DRP{(pԑﱩ?dM~[O#C,&mܿMz֓ QD3-+Z5BSkͭ[#4FhnIMriK\$&Ȩ}m*RVE1s|U(N rڤw^;s[^: ƨ<d 4tCzyRz6S/a_gzГnPA7@fgK48,y3*=v|}0uȆ> stream xڽX[o6~bl] E-^>6h%&;"%YeV(Ї΅<'?L޼,HK*ۀ`"Iy0 oީ(S Y tUS%8~PN;'HLl2wژ(Wb8&MS?yu-? &;Oݗ&v G򷙕EdE]* ixtx ӄ`*vL&*Õ)yZbI$ٱ1I؈QK&]e, 9G1$u=wC&CrzƌIdr"<-Q:$q~(8tͳ)"+A8 uitVF$6k>̋#~_ ݔ/,0'FqNI@|^g˴(&4RJ~#w*#c Z/=,#(p$0lF96}u2 G2/_|a`]Ask[E[% H$m&~Ӽ6==:&&#.m$0Đ&&~ʬ16BA6{H1DFK: EtkNɑ<"8\l+Ër(G7oEQEq_wUhܲR( ~$M{K4o]thm=WF=\]PL{SNqI NqFwϹIKcQ p%OMސ5=3r1DcgMմu.$#\x9 FsjZ^/aPOZϲ{:aV endstream endobj 3257 0 obj << /Length 1044 /Filter /FlateDecode >> stream xڵWmo6_AfW4CCQ`/^*hlOR$Jdˮc {(O_kőc#JCRqxetn]]{myn<m$H[L!>ndYZ'J5rVKq%!]w,x6{matb{ou/ajQ`Ce#07+qR`Ea 4p̹*6-a)ygcq $^ OKL5<2x릳8yV<5 As6 y2?A+FR4ADn̒LE&IdzLVsa g$&ChĜ Mu20:V^-)̭2> n(Exz8ۊ7ܮI?*ܯ*^c?ˬ[Jw$TM~iz+"YlЎ"f ąY9F 9cJu$\Tmw 1Qoe0B1%TܦB" Vy½;L@w=ތR{E$(3 × b+X3\KQrf0ɐ޾M{SI.<חqi\lf :|-5 endstream endobj 3279 0 obj << /Length 997 /Filter /FlateDecode >> stream xXK6W[dK<-ЮۋŢmmei+ɛ^zm>hdQ3}PmAo'?.&( 6)X#JB!RA-7~w)5Eբ+|mYP+'6z1{BA$6/v A!<|ct9Fד}k@.J)i0oȰ'vF3I2^  t`#P,+4ai1G5Vڽ Ypc;c|k 5䁛^i),y;ۏ\gf$dz<٦iUyL;gNtݦ@3Xk}JG5UT.<Ʊ2{+I)}/1Qur\;]xo{ )PG$(|v! 6ȂUa.(,GV'I>ҘI健ۖ:tY 4Y;d}ɵ[08bA 4WWXTQ>֥60|I5,xySqIo$gFٌf_NL7 j|Y/(۠0a}O0jP5|(P5KGM|*zĬi8Vx*ͫ"?օNs66=3Q*X3|J.u @5 =!4P51޵9>lOp̀0Pty1‰KIZ%~טIU;XE'rDi)5P#:$=?EVwZ'κT}넌tkfaH+UB0 ^C ~{%uRRfא+#AP a0ݎ/v۶4w_%lzmwe~^3vhmsUj8*׋?o endstream endobj 3300 0 obj << /Length 1165 /Filter /FlateDecode >> stream xڵWmo6_!&K)݇li A%ξxHAwQAT:Y'Zm˨ho}mTr$fHi|/iZ=˪>Pc: GP!|C~׹Q&iyN׵*7-ͻ\ERn R{,3 uh,b$wN_o/@ k_;{ |H`X ![ Aй;m8؋f toqj$c%i>!Sup!b􏵟r7<$7cvrWۻJկsj%Q+LUe{BPY^h۟νc(yVzո-!D  NZ L:N%:V<ʣ,;YvSuQ',Iv4A %G8R~RcUl`lEixbSn@gQR٪{L i {zھKi~h~qZRm(7,n>-ogonoMٟ3bjINϖI#GT_F4wT`:̙s=yg9rdxp30Ad'9T2#\sUeb7*x d*[bǪ9ֶo@Z=WF A[窊tSk~t83Ͳ&*Zfe"oV }N׆1T(Xoh^Uwmtisw6{(mYiC0y0mp#,ǡAb:p8z> stream xZ]o[}ׯc-(H6A-6HЮ}w#$=Cܫ*@=W|+go|B0! dbH*DRT`\1*1BhJwD76@ޫ!afHxr:c:*@.Q '+DH%V`NQ)B%@ITbbb1"F $U; '*a!GjHD8HP36mF2Կ&)U)XТ319y ~ +HH⌛8࢐ GYsWBOjDN^"VuYgXTt,F66>a :6Pb6X\dHuo.Z`EϑɤuM>b:4bx\lRR9`p='\H*bSى}]!H8Pt"0mqLPEsJ"ǂY8ԜkjƎ2*K='d.uUnqfb@*V,t=uX|!WwϸZ`l >Zh2}CgOz2}}u>Xwc{v_ώ}}L_ugksô )XQ2lqzOё6?/,ë_}]-g̏?N۱7,ydg耢VPb[uFwCF>49aVoA(U r q޳E@g-pxVtWfbJwZFv_]^}P;Wq6i^##v ~6F`s쭣WINC4hAj{8./pXX_ cMa/Du{Д$yHQvj] N d*',5}\(Ҏ fJ(*?# ?]P@GZ $}Br 'b l.gՈFd55LPbyt"#^@] Z;2ĊT[(, |C4>9;]|:qѝ|\\>>-?O6͖*r.ytIޟ,Y]k6DZ;lb{,)Q54,++ȊS.}An4"9P"PFAC/(@G>!_d`=D5&nBL ) qQ~԰Bf7#Y8äJaI{Lu83:QA=P1eԸճe7[wϧTG])(t< yӀ5$h{$yM>$Ɔ\A!֥2&)XkGl}01͔t(]qY0H{'̰}'tSyOseD{I_Z2}?/R /i"o^~׷RDZ)"IIIIIenjENjENiJUڨF6F1.cΑ %G?YJ] (5]WBnZ֝q[=b endstream endobj 3383 0 obj << /Length 1251 /Filter /FlateDecode >> stream xZMs6WHhavb0Xaps|]$ E2>a( E, Yn2/\S(v 9/aHw[ۯ""kN^x1΂$Tt-1|oC2v_?ܜ9 zgzwg IJ@#`wf=n>2 (܉gy7/f0DgpM J'OEsc`| Y^:2A3SAg&)U=*ߴPB'Bk50$~,#dVrx]7 yBJ7$t*tBKABίޠA?XgTh=n6,2237;{:`N=[4K?V1 "@z{$Ga~~``VG%=qp$9~d9'C W*dMtUEGMc1ǐ@;{{ Cs (DR"c u AޠZƤ, ==  0P?H7l̒&'i0G3-0Wg^8[LuJ b[{{fꛡ8#ool9v߾fjMj/-~J$ <6qZ <9my?TN~pI18)ߕ+efe1xrWU>F5C ^&!ã)"'uYU[}nb}!*r7{{t}|"u|:U!}}Ļm6s[*)|_H0U«[nn]nD\wdNujJ tSgcgɆGal[TUcxmy3 C> `<6q{MUUIQTL rWgmU0$W?Y7^`9SS:F$*/?{+wK'vJ {cWn{أ| wO/\?/{/xGcxP$m{p864^A pGÍ2/U8=7)A4ҝሄajwH endstream endobj 3309 0 obj << /Type /ObjStm /N 100 /First 1014 /Length 2740 /Filter /FlateDecode >> stream x[mk\_-tt^ ,MH[Ht&fmOKe}@553G=:D%8:H>`JӁ)(H9aԢ\:J.N0b+؆g[g[vGԂ9:btTEGHRt-28LϔQ)|05*Qӗh5]>UrR5D$ǡcʎg̎s:*(|Z$`JJDDN8&NrU]8X줱2EB(((.g}-ra)\KǮY9FKQs%_MEJp} fڏBU^П(UWk)z R MRXӄ2sVIv{!d]N*u9 C(8`Ȣ+pby1bc2,9uHpHcLMde;ܗX8[T9pHA*Vz]]\.Rh {$!U\+s \ 0a؜)'ONorﯯ׷'7wo?,~XߜnN52w?-xvՇ[w7,}i߻'O[qv^tOO'vvwYpv݇W7ѿn~?>߬o`/_竧?ǜfukY,o'ח/ zjH'X T ^_AnN-W~4x`X[sj3G)yosV7W n{448pcz|(v8JQ]`I:* = gjy}>20Xa QP&Vrp.A-!!S{Ez\ LȒ؄b{x$D;y)&ja{K.}7r ZK砝kVx-wxP{8gQ=T$nիBG'sĢxl^Е6B/(9ym(ktltdpC5AXڡrn2/PkU{]}@XkAϺS˥'-CP~RW7oV`x[]}u:ūo7*$}^mlۇ_V_\w4 ^7x-6]m{xz blbjI&L&L2d2d$I&Lr2$'Lr2$'Lr2l$If&M2d6l$I,&YLd1b$IMr6$gMr6$gMr6$\Lr1$\Lr1$wrdFڹ{])緳gG?0Sgt DK2D|y EbTM Ͱ APڰRn`h @(N+a 7 Ψꑞ$(Ox(񊐈^DŽ=cCBݓJA#uq5$FBĜp8TO=3+2<AQL ݨ;>pMLmI@*!j,^OL(&#D.TDVOT*")#:}=/ X4Q64#[|`ljؕ_Ԣ3 T#+DmIDp'2O)/u!НEP#'f ]jmUh"l#' x*g0Ue0T(A;JR'|(ʕb7+t:BOJrrB8s(A=eE(SEM/&84g"h82s`;e#5Odϓ+Y|&JƾoV X<%B9A7rI̟e}׫'1GwPLDˑե%8+Uߺ Օ ] endstream endobj 3490 0 obj << /Length 1758 /Filter /FlateDecode >> stream xZn8+E Ĭ(bA4A<8-fc1Z2$9m~hI%Yxc b}{x.Ec4G]2:3a@rF.!tto.o>OΝÄ:ȥT0 {G@|N q(^n ;Tmw\b: vD2&YEj9\خrL 6 W\ ,Cmk2ED'ĔmoDqW YrauF]iݴ:6F%Tf9H0IWۊ /+06HBZ3NnN|^ïb\֪}D;0Jr5U[׮uVKBPz)\pG~] }LR.IiLu/˹C@iz\1,a3Qa'7m~t0}푆 M$?pC\G\Ȳ)m1y\o475A3t[¸O('wЀ/mq H7$`"$4,]د^? /P0㤚NdhB ل+bF,% endstream endobj 3631 0 obj << /Length 1600 /Filter /FlateDecode >> stream x\[o6~ϯC t*@^)ZdEl-;| lyhr%ZBQ5C?=xŵOzHQA{!ٻ""~5oJIe(iu3~qM^{/}\}I6=wet @0om?@.6{|A =ܠ2}d$-}g!."Tc2;av:=xg1VAN" U_yDO <2U4WFRjrOLWl}Jݸr0KzP[f1mbE+ [~Ul.W^׿}.0W'dp(cvmoƏKg-`ȨvB>{A\2DQd22-jҌ70q#fgʹIvi0"y IpQ$Cimf/% L_LhQ04 a 8Kr)|Kl$` pwv2%sILvAce)3H娋0և]h9c}R+|C~z(86#݄y_77i\FqkAW6_f"7GT8YYgw@wm ykY9p-ij[Gڢ6Ԛ-^]Hv ͊6șf쉈:҅b}+a}%lj2NDn&"·E)O%"k;2y+K1%JK`tr"Lrk7=ٕwU YqXm( ИDfq`#) Dfjy_#2K/ ;X{g}||\A=ʌYZ̐Ѳt[xA"ѕlv!&@lkvVujL5=o,9Q? 4<)`>̝7ǢLϮПI,R<.{;G,*G|VԐi4Kp;e:2U0}s7ٙ  +)Nh RrCehpϻ",IR >UqX s+xؐ&Фq>.o-jƌb $ n9a4~1_t9.9Dw*CX B=Hf;_tqDPiF]c'l.9J0Wk3x+1\!yuu.]uW_7($1/ǚLY..8ɺl}ᨰV8ҵ/n4`]Riu 4aAA |h&c@IrNJhZATvBWܖ[X{IZ^KkI^KOf,_V{_ڌ\bqUR\`br n]0E:߲rYBjMQ Y Z:`zM|i/M4ʔѝVaE#oLU )Kp?Y endstream endobj 3492 0 obj << /Type /ObjStm /N 100 /First 1026 /Length 3147 /Filter /FlateDecode >> stream xڽ[Md2ټz_`0I {I/ &fڌN0!zժWGI[:j}xh9REFZ^QjH`4RRH!Ev;H9+"= &7{aJ~<׋z<7 עtomE%=\0G 8FV4j>69V^hLb#)0GbTV` z'JR_jǨv 缀f9⽥XCD=k%%x(J+o{~F%[KdI=YKX:ҚEi=-ҫ(]o1Q? P HJXô[fX>40/c(Z*^/RFfl=[60{=mJ4ڛ!wPs~< 8S0֑"CZUfv j`jmj?#`:`6)FZӁ0!6_K0`4.Wi+0i,UUM=#`eՏ)d5rwQa@8^^;O;}w?'~ygo?{·v҆|s5Lks<7@{}1\As0._m.@90<<<<.T.ʁpAp8Y,D" Bd!Y,DV"+Jd%YDV"+Fd#وlD6"Fd'ىDv";Nd'9D"A r9DnDnDnDnDnDnDnDnDngo>=#>/zw|oswoSݿ9!wuuTٱ'1c/rër'Ad,pkq->mۡp[`:|pJlXm"!T6NҌ0ٚŇe@@\aD .6FԾ~X^!_bMt"{ѷKw@렶e>`p )7ʱ5 ! bmQ""m >ʺR LAn *Vh"7XoפּӜmmHߎj߷ d&:[:|"uXdbBD EEL,6\ a!Jdd- J6 yX.!&_"qP?MƁK2b7Pn(ED ̖* ~%Ǖ@Ņ2R^[PPۨ:lemTCLYS;l!ϖڝ}p(*] L Av}bAgR Yzpי7HkK;zJawDP]^HgH[ID%|CRZ >RLfBԅZU]O+L*\'fvydq/eRa"ftX>/b{:QA*%QNbaѡ2lYWPsUD)dak=ˣ:P}ԽN<[xλsgiǁzNR $̍:K~=b2!,_k&='dj-aUfaTzȆrGȆ>lZ"ʃl(kH4ۑ dUjp\a㙺ڰH 9l&Mmiu) ^cL ]ͅ~\h"Xb hV|I[0M oW=v6Pv DhPK6F}qD_[k4Z}eNL+)kNp'E`]Ǟ+?[v=`"3-띄Fz~uڐJkrkD{mDl^[rĎ1U/c@/%>f`z7PLTu< =, 3q)nn,9ZA%Q7A-2_Pi(k~!ծeh'E+ĞgĎ|I!$7:ݶHy9$C+˽UW)06GHT&J)hOK!,O9c-♒Vy!yiۖX\3ڗCjۺ=&yΡ>SPQѽ5Jq! endstream endobj 3633 0 obj << /Type /ObjStm /N 100 /First 1014 /Length 2105 /Filter /FlateDecode >> stream xڽ$ :&H, 81)m, al~sq;S]WE4Yj )d(gEZ /4qk/,~@@ WMz7 2FB!kJ&~.W9pw%r{Õv<[:Ǖnl~Ҹ?Kޯnt*%oީ]4UKFڸ[ * \_ VZe E{LA9s9O`1v>4NWP-KF@jw3B_LE/毕%4>r>o9PlY5ZB}( 4] Ϲ]&e ~k@i`(;|aaٔ<XpjAW`<\r7Fҿ` n/ x@z1x@zc_/EL< ˘07,d*Ho>~O_ݾO_n>=C?>5|īDRSlj2 Q6|C}n×p. 7 6@D,PKĄ>P62| ?a KApʱ&X D9 s ~B7B һ()s=A;'hUgg F-2i1t@IZ"÷E8'7B*@ 2Cky"T8+Ĭ% gahbIb tհh[AMXUv:k;V M^NW |Iq% |aWFy̖#y3!'􎔠GߧНVA5BvBɧ08kL>49EdY!H$(@h+A>@[ S[(@[6&2 ؞"g"YX>tI;hn,LcXEK+V'BG3uw XS ٙ5 fAnW1bHq#ώG'3'gXIydiUHkHn+!`~` z_=biQ "b!z`¡12h:3ƹDE )lBɄ8 %k^( G,_2l]G0?!`Y1:8B aW ;G~.Y`},vEat0w$D{!쪚'a~Re5E))6`]W pF(9E\! YAqqB4ďT({bߗ;!2d=E&Uvql;0%}!'WKNR;'aŔ #\ &;1#U(Q)M?kQ{CC$_ QW1'odz$L/Ry61>|sع $D4a6ijA@,_S6/8Lp~+E!К?)~kaDaR2$WSdrO?H[AHC.XH:Uc! T/h2-jHTߍ2}(*RYQ^gϰ/iC!!v耀MWC dc"gv5v5*aH/z17_uB$Ql'msH$0G/@!I& endstream endobj 3850 0 obj << /Length 2231 /Filter /FlateDecode >> stream x\[6~_N4A$2>02,MK[G(JH"cυ<*Y.ū7_r@270I&l! z~wKVKzcCIԞ^V/~\ߦRPDA+ߗ@,G*..Mqw.;Rs\I4LԊVmSpr^&CƲ`(gv6A5= r  !5VL~lh9' rG yBh~q >GB䔅H iiA=Y  =4)uviMA,/~SkTK:74A}/l\2Es':{-]ɓ+(:L j %T*О`r2o7+?AX +C\rwgp'%nL!Hd۝T~߾U6u`Axс$D2"|O-v`ޥۻhzrdYҲvS o JSv*E[= ^; }G^~Y>%I#rgL"CcO1M,~PIWAI$Z vx͐2QD"!S (;H ?MW #JVe0oIFk+Vy\NLwUpn֛&OOe¢jѺ:$Fd'%hx\- I(фnj~M8̅OAW,c` II?K]/4ÂJwzÜL˵y 燑/koC6)TU})|U`c> ֌ @N~PYT_]b}Q>OtqRz'c3R+ˋZ6i-C],B0 S AX;vMs*U`T8t.,<#<~v a2=Ӛz7z^$'!!"a9^/0It zfuHhcRNM( ג86Y}U.J, .``@6 ~띺M*ʨ^nr{4mw]V Xzi8S*!IS*OoN.UX˘ GĘ bdMR׷DķHC&2wQg]եͣkgۣ҇Z8R>ڥ!v{DDPhmuJ!\P,zs4ޒ *Zjj/~OWRhv-+b^Y|1S4Lx0&ո3t*f"Eh[ߛK|u,-i4% \)oăq}~\u.V2Kf 2_dn+uY\;G:j38 qh0nߦmq NK02Ǟ+vFys}i>4iƊUv&ɳ{6H:fO#k .WYzŶ\%Z`êQ3q.vU譫>c<#d,MӃ:o񯮣cSʿ.I.gD=WjnJρ0Rι| o̘H B{Cb yj.ee.k^ !J [b9ե kЭ;S//.lWۢz8OIg3d%Hr6 9G/?-M&˸W4ˏ1 B§}hyZUishЯ*_ iO7^~ endstream endobj 3634 0 obj << /Type /ObjStm /N 100 /First 1027 /Length 2767 /Filter /FlateDecode >> stream xڽ[M$_QGRSYKb0bX@zb3;*:#*cjJGZ#cDN`^,i$YYZwo(3\7JI2H4v&%:ߍGL e*("hWuME{!=:w#5<\D`[;Sq|-Zf65ҶZbmh><^t]ϡx6j/̣j{ՑlV-xCՓWٮ[V_hd4|ZZ8@|j 64{hf@!iE9K0,)-7)b#w"DtgȞ-~X Fx`)^H2v-2Hp D#@kR#K?КeGN Z5#sCkڶ i:^Ѱ&[&8Zkz)+_6!Π1Hs^=\ߏwO._~Ϟ(o/ײ}xk0=T7,[Er3CYOӫWe髧t"o1}[@,C~7>s \g?H2DyʡuZ\̬HSMP͐DmYs Fyh3 /}eOtrԗ%r" IfxQKR\&^<кPt>raPd9c! ŜUWLE3EygH| ό*JZ@paa?4qYQ(Qҵa ΓAVe3xQ-+w#-~( pơm/LΥV ( ]J󫦞Q`Z83#O| p'l͒$k1[;^̊$la }p\oͲO)`j޳g[oݴY\$A>'Qem~+WqI }] X6ŀ7{Ʒ΀6q@GCqsr4kChVVِF,tB9+(}}Q%(Z00!mbwhMcMK#b~,TzcQ%[{9H, E7s#7}E 5{Jm$̻-/~Æ;] &?8ʿX .o?}#ا˛/^W|Ho!o@9Zz|Vso|Kں*fl*7q'sp|kP;㚹0ʠ2h ܈܈܈܈܉܉܉܉܉܉܉܉܉܉<<<<<<<<<;lALs'ڶ0v[E>fybZJ1OL:ȍ;uns,C`ƳH@3; Qk샃DfqX(:YfKD}h=H9 $ õb-lʷ7$`s,IAbOI,AbOIz7~%[7R/!#A endstream endobj 3853 0 obj << /Type /ObjStm /N 100 /First 1014 /Length 2231 /Filter /FlateDecode >> stream xڽy v湒6`pLpX 9?b'` gndITxD0%[ (Io1dc ɝb:=QquMD0j%{jZ%cĉq$Qo:MLbd(FXƨ&|aԂv|w!ɵw! 7敞Ւ1/ r:qV\y\gZR&>l qZb%5T,TPIr7 UԜuZ*_ bYML1nйųYO]0e7P79`ǝ]2n^_m-~o !nTHt&ѝb6VF6T^1y giCɵ )Weha6gmE>d kcٸ _I 5W@n?O_~?~}cAd(?O>RVeA,bCntC/S&m7ͻd2ɝE ceZI=[`.~6Bf_  ,APu.X|П dP bK1f(%;t mPeF8]7B0 `{~L ;W@> @V^1%d $%CP5G6B@sCk< c."o\ &QgGzFmP?m O~cG܆FrF'@,(("N]6d AB1;fG(#2ZFKD͂j%mp [ ϨkL1Wds&^Fy7+Q'BRZ"<`bǘ `_2tNB A=֊ ( >$ɨi[YKv&.E/9;%y"(2e'-/ y*oCSXh@1zOX.XJ"i2j%Ё(_%''hmc*9'eԗEN pxhI-VFP 9:Uы:jSfcP _Cl h)%o,4}@P,!wz/Bbr-HS;t6B8tф9mS&'N"{(vhA-46bgǣ 'm[bMO" }-"|O  e8Cw$͂@ޮzzLW*Ob%D{B3t/!=f^148lԬSslKpLz0t8hKy' J qF6pV'D!\QPBę2|#d[WE3qrXt8]s9 ;Uq%Є@2m]@l2 6^18h*BC}B 0ޖh0H!s(a4!]Js SL-p{gNj=tyRwx3?Z{ 4s1b^ԓOCLcwb 5IxV5R,WxhLbS5!.TtxR-;(8z5S<=ǹ_n=Vw%t3^ ˕a#!8)3 2S\v_A2> stream x\[o6~ϯc̬x'lmҥhb@V5~M9LQD^<swwH%ݎ/O1<@2F7#E6r:zIߗoXDSm:c' cktI~˲n&q8*5 FǏk}GAV1PQ,P W9 Djha .*K@ԟjOIJuBBZBe==ik!rO8UFRTU:L&*ZQx 03JK sV-ilYPAUHVq>|7cko& UbΨUbR#}RRFY@&dN?  쏱c+(bmmĊĖ:OH@ +|xTʘP%f6d0LD2?20K ()P^AAT _UH|MOov*.="Q!pb W,TV `|*J!lxQю|]- - Jڞ$^r*IZaMPf.ö[m$hiU9P݉Y=u]^%m/ЗukuX|q-U뻽JWFo:C،֑XɎ$ց9̲4-PWcZ$q4֫!/Zqc)ֺyUʼɍK,popB)R4ojn,NM購1ikOȓULkLo͆(䬗;l^\+U$LnE'G;H?h0γ׳u< qw̲;sؕ]o{i ֋<.+{ϓ4CXYٚ(6ē/*[(8/9&p.BM.>ITУ+|ׯ.#[hyf4-84`Qȸhf\mzȺ >=޴ͅm<{WQke|>}PYh*#c_z~͉φ=j- =kGba|DŽ 7sX@ojkُY"c F?>"4;Y||u2Lg WtIm`U}zyٕ endstream endobj 3854 0 obj << /Type /ObjStm /N 100 /First 1023 /Length 2532 /Filter /FlateDecode >> stream xڽˋ%Whl= ?$`"c7ty;/Һ ƭ+$U{!nARBbڼ!!G񆆒7R{#_*RF Z6zA nI4ڣ9yժުAZТ,hWo`ڽ8O^2%BpN%xb FUчMѲw*!kuz0% ZrQCSȵr>hM7Rbqyma:pKҡbTUWSC,UWjNTn<0}wqdJ>B98=k-zNs(a_0mPO\Ga`b$[L?G57d4wZ ӔO'lSdEtyEo6&e{CoR{Bo 0Л-TݞzCosO}7˸i> 񚐑7.I%~zKy(ZR]t袣ݺ1)hZv^w±%;BA l??"ӟO9}_N>1|U7'Ԛ7L|!o [+nex* ?=}o~ߏ[O _|@!H\ J1 ,(mPw5e!Ek[ f,4HU+[F@$L^ !n0-sVB-5Ģ 1S$YhQHK"RibBmS$9D_*xu-DȈBMB}f| b!f7Uڷ.Pb^ (1X9Py׭ sߘd/D\8M#ը1^K0K3DOs2f#\?&XnP BbAyG F)LR0dN)ևLl1Ri%cA9)?S,-K_,YlU_bfTK>WW_ -NU湺:Ypw1,-)2#~0%5"DJPJҽ΁bưt vNb0 3zrRdd) P` =ɖz~a(Vڥ `A#|mʰl|H&m+3GFqk)/kjyH4*.;r]6'?3 ) ֢Ԭv`y 6~ F#T Dd}"y |LS ]YX4< P5C/ P.m8 ^QA_On?t `J_>_ qzANoyNo~@5zz|a?p?q[o?WϿ1TU44 ~x98;7:vnȆl$62 *g*^*TK촰N+;촲N+++++;;;;;;;;;;FeQ٨lT6*vV6FfQhlt6,T* BePY,T*+JeRYTV*+ʉʉʉʉʉʉt"DF'2:щNdt"D\\\\\L4>hA}F4>hA}F4>hA}F4>hA}F[|+QEbRdpXtfI4JWBh,:cXfl (=rM!V+THe7X3(qk9BВ.vlM˕ %~"vLV~+"G _)! |_靾ߕ'EvB<) qpNrR|@O ? *@EtP0TL)V~-m^"UX'HbI^}eSt9@isagc#9l QoAü+s!f+F) +FbaR#崕hw:>)Ŧ+OwpE f)#),6d1R0X)V:jͷ""q驻H@;U Xh#yi Na Q"] "ҹ@Hc R%?n:NJ?RCĿWC,Qd]:•+VF+߱|@hZbeߦ6qVSI0V U.mH Pq.lh9ܠ( Ï(:G;}{D R9E鹨8(E}m:Ѵg8&4l0hf?!+i*I]fn[~??vC?LG"Ŀ )WA2 ̡`w۱aEAbey@}$_qlyx/7`6AxlNfD=-錉 endstream endobj 4159 0 obj << /Length 2257 /Filter /FlateDecode >> stream x\o6_Y,Сi4àڪM ~ԇ(ɢt-࠰w`_x5 $Clre`&B\'߼{']5~KT5H`GAIkB*ߞ>E\'.~66/mhOȟ? &ll)Ϋ?RFW%&SDǜjԺ՟c>!Ĝ<<@?)BS$L} hP|I|ctk{A(jx2@Nq)40Z8`.[+Z ǕW` j]r$Bu"*ܮ b{Nv,綝@Ğtm;Uhc5X ǀNWr:73 \9]o\RyEݒ Bֽe~S ,5uGY1ؤN&ρofT0XVJGK<0CR1ZvmS{CC9R*>ひ`Bd63ul­S]\)&= PCVNϧRwI8_4 𾈓#NwX+KQرs,5s|#)X*(sk8IQ%0;@IJ߻jXɔUxm"ϵH07z*2wbW] ($Py?F1vZye'I{#is- MZYMOlZ ͦ{fAٯ+"(1|ps՗ o K Tڼc:Ԛ)@wjTmxEl |r{'P<rrY4YD4 =޲8Nl{VsX!@J ; lݛ+Yˏ;)rل"* XrM~69Rt9zp ,14.g4 ,H8Fw} vzᗠ^ ^ܸS?@t~)DBceY҃`AmBiG3/g%'GDcYc`>4c 1`,n ֜R?XcGXΕw~ q!>,mF22FGzY>/qyxr(+}:FcX)1'f6(!BC 8c7u"އ`-4G`{(]vqFFMZJ0FGgjcPk(Nrq9Yf l*mdͥ9m槡! VS n^- |H7@ cAmۡVE4[#V?}M6br-$vkaqΩEID=*n?;Վ},ʏGUEe?cF:F>_ ԕ]~t:.C-Do{giM^&/otD@)D{neև '=P4 pKCU*(o{MbTC87\DW^ ϫ*c[']g3׏/&n6En?nԍA|JSzLݰ6uc$W Ƃ^_^Zz޽ vd7f[UrΗ7ik4ũG:Bz[=h*9W6=S3%6d.;hi{s,O7Q8?qX -C'J+_Qx0fhqOz}NG1`Jniuḇ:ry|zR^[۸?&~ewQ~(;lؠHGIk7]S Qu7I3|>sa@,m@6qր0z]'xGRm^m; ux?'@WI [X;=꺨Yݼg~xv)v endstream endobj 3997 0 obj << /Type /ObjStm /N 100 /First 1014 /Length 2832 /Filter /FlateDecode >> stream xڽ[˪$߯ȥxal F B Ya1W슺h*-r 'OEƉGf$C@W5Z}S_1i0$*|DhF Hn7k->D)0DiMDL0ꉉFbQbcu$[p >`aJylֺsah`c1wYSM˖TU.0>I )Ɋ:j vO%?d֜XvkՙJK6&Ti+#UVT7R5C7YinX,55j _k*yfMb%V:uiT4u#,E(Xneԫn%nsa}Ⴐ_W%uwG ѧw֖ce xPṸͽW4oMO \}5xpӴQq >5GD~6ܦ+a6}i`ή>;XpFb1/ݯuaRH f{~yL߾}p{/ۂPۗ|p[brڲZݙQu/Mt{y>ОaםC-O9C\AYs\< a2 !O:d Z3CՄWBρlaBXh=3d0AJ+ FɈ]Ox8G(eDƒЅedBd##"KRcm\ 33xB @®rLhc&ҍ`YNITYPǬY6xqJz&2GN=}z 3@! QګΎZH Xyxei $UZVIJV㙄"j;3Z>FĦSk}bh4zNVjT^u!d^嗱b^^틁EcW^BŻDT{j9:<%Ae\6h{IA 6@gŰ@)(/TWz%{ٻN{:r'y) *c}"Yl|dHhٴ, ". x=a)|+KO>֪wvPGwɞ|'iIu Ǭ,f6WzAY]:v]%'Iwy7}R9*q' Q 5A(H1WS*hVxFw>`9l<;C٘r.!I j?@,Rŭc9*|դܳHk6Hlzxt5<p}$FEՌ;Gi]*,(ʫjG[EKɷ+,QUpRkQ~dsL{?ܺ[Xd*kԹg'I-,Y qc_j\c/i_Ţ{,:XB+Xг-ʝ)|!l W"¥19Fkޮ9frcB=@eau=5taC y:vaCX櫠:'-09t=Zɭ"p 5{UAA B,H_D""-R ڍrTHO9,ݼԆlUtճwM֙H.ۭ`3mkxv/׶;"V2%u!PTTO;-}QXX+*KqrT#g&";lQb"{N"{5vQO J~`PS0ϧn'vd{d0DJkFY)8T8<ר7ݷ Ai0[n.RS`~G$d}zSK7Ow [>g2} B̆,O0$ט[R=$J&Az=9UEιŸ<Ÿk#\QKܣx@6ƻtL{.9vQP`0֗4;9%aIl)#vNI4]#svN9,Ʒ}Go7+y?%B_|ů~[PJ؈7<Է7~ÛGpO/_׏~H%fz|e?}|[?OiJ3&;| cbt[Ǡ~Rb@1H 4@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\r 5k @\r -[ @nr ={ @r=G @<y#G )4HA RhB )4HA RhB )4HA RhB )4HA RhB )4HA RhB )4HA RhB )4HA RhBM3-* endstream endobj 4161 0 obj << /Type /ObjStm /N 100 /First 1014 /Length 2099 /Filter /FlateDecode >> stream xڽM7Wh9訪$ !03UEfbB!8yKG[w>8uxK5 )Y $VSBjU₂)\pp%Wٻ$(W5PއR靴@v𨷣x_q`1oG` ʠ-XP lԟ 'Zj@9rq {0Qt+LF c{^7~q1].~-{n_PDy;PBc`~H %g{4ME˽Lï)TTk%#g,__ ^'j|ֲ W+[P6Ӥtj>nռ"AP+>n)OИV٩*Jch{` K}k=fZeazVzߵ7R9LϻV%'[zE拹`m:`3+Lܤq &70r_X,GmhTYZ`ĩ 5">phܗޙ0ko/pcb니"7o^n?pÇ^n?O훏w !ۿo߾a%"aI00T)?TYMnp.㏟}}޾} jXвB-SVa3Z4}L(^AQ0ItC4(U!=iAZSQj4X'+Ҟ!9C3)vKYejl^Uș͢CId&xLphS=U4D&H_Ȳ0[lQ%'ҦBvyIXdj(M!ɰ `'FIDœFJ %ࡘI .6(0 /SToEIk `1&$FF"zRbm$RFL:A#.!f$΁ \jAG}DpFTV rC9e1k C:Y )hrtU<zݳB(ig GFi7<Cսi(S&TK%JE9P78'6IHR&kZIF9bKf9b%N 8B4N&߹j1lQ^xZ"d׊A`׊!oAp?Y1ւ&ɹ LM휇 ^2ɝW0Py@kW@\y+~ZƬ,QjRu>(5b\es7g;WdBŐyП C/~ bh_ w*`* q? "WDK,Ϣ%RZo h9)fXRWuP?SuL0]á [NU7[1 Tdn`0U݂ag3UDaj`(5FZ =d,J%ŞsFbF5G):~)6kWk0Ԓm0 aw5u 5dj`_M #L-!Hǩ l)8u/Ou ]&Ōk FLQ{bir~ۭ?3V]TNmݱ[\Ŏ[t~nL-ϫn#٢&z8xGXV?焘ޱ"N@WE.Ƞbf%C NBW?K=N9D.0 _qjk>Tg'rF@jC :53;8dH~ WڳCOȆ|ҧRyi0 p <&AIVp5%DŽsЎd8 endstream endobj 4339 0 obj << /Length 2321 /Filter /FlateDecode >> stream x\[oܶ~ؗ]FA_ҤIQ7ҢPvNeːdvW;)$E, i437!"XpsH-8a^/=XS z>vԟRz~yxa#޿vt7kuᥗ7hȠgv2 )$D 2ߒ:>M!"JyCȋk${2i߾x`@TAxQYMBԿƱVv~8m|}e ;'r#j2Њ\ick00աɃӑ4̣s6zPXc]c0mc|QOЪ=,2 HhUf6o0FxS*'A#ܩ|X=[WwKAЌ*_Fqll $B{,V&ea:}mԈ9F~u! 8A:T)rC0WoWl@43>mX<-V[?՝T҄ ҥbUZ.`5&uo` "XzHЙ'WBHPXB?dYZ|KzG8?}(ֲMxc[47-Q uFGF;f=2t50ٴ7l-:#Ş,+HbSG(dak qӳ(j5׮*?x $* דma}ޡ13lL{DFi''%PgՏ";dBk@آ_ ~e1+]bbOpoUS)\cKD& sJAll߼ҵkDhö6QfuRy"\HP`T[]i®G2.OԲJKN;`#*OÏۄlm* !BHlQOE`hŃ%n8Hbz{RGe]$u a&tϷd-}wh8T6 *Ȧp9սJgT 胭&ݫ]*Tz'w]ꋠ!T[rQt:-jZ(v/6] (|s揩b!A-MIWXlVp\,(>~IY}3/i96TO"d0{A']7RƘ!҉0B-ao}Rsq !z`d/n}NIv9ȗOɫ<6M=/vG ʻVOހh{,_'·No^;#ۀ1>}a0y.K&j`1Q\n{N25+q'hUbj$5>L܃0ȨQQZh,R76GIH͓rHި)U1W[;#\} H):k4"_QcDž=骥l@bY:SC"g%)ލׇuQP'qb~k zTVM )ۋgtWzF.ö{\1oD܎ob#[FMxqa/j/(bJs*I-8}£~FSK^Qifkg>mSohyx9 TPcozHTeY cqʤCd endstream endobj 4162 0 obj << /Type /ObjStm /N 100 /First 1025 /Length 2881 /Filter /FlateDecode >> stream xڽ[M1p*??$@N {1,ο+ҽn<&UɚF )4,dUo zQ=V5=eo0Լ!!ڽ!KCΧ/rݾBnS9~9r"xKY ic q܂&AFPg%)h1ǓԆ&V1>莲}m hs57̘֝OU]0Ԃ[5ٯkyLl4BA+*I Us.e_R|S mOkcn -mO{hyC|j)2ZSlm{b6V6⋇5 컘YVN,8,iv0T`0' F#fZFSZbœ`h;b4 5{}1ZfpKwJOff>IIMNc4i_,uUˋ&FSi `ihj:b4GM7ja ƫMV՛! k0ъ~y ߿p>\xDzwo/>$YrGcLNۨQ@ëWMS|yD?>{ HsL$\B7#b+ -dQ56-w=EW! Y(ɕEBvXh^FtW}cjL`! Y}2>d83d:4Bbd u#aPRbT(c e,'DڞN RQ$&ҩs$/*2c} K(R ri!R"91iH9m5,=bJ>i"8 Rg.dU?D#W8Dw$ s9,J47J,M-;j{Dbg:zq+c RC $ȈsHXʈ([֘=[p('/m-JM{IlK}H)If`v-:.NZ5V cx[Lġlr G55Ĥ{AހK>ÿo~xkO{3U|knd8gW +v.\20n$һzx;s=Sru^`XJ6s.b˼)glk;zbG,Ŏp۫Yz86&L5wjL ߓfye3{W9%~JטĎ)B"k A$bQ3H5dt7`khH/;e7TD]Y#"C5:0y8\Y9Tbe(L~j:B?\2b$Q7A@uG;/+Q f@h;^_1%93#* $u"[++/lkbgymeexתwv 7WmXYoH`7uHb$! |I_n?qcen$\3H ؕ[OyvɄOHl?6;䰲p7J~s~{?M 6$|c 7 endstream endobj 4341 0 obj << /Type /ObjStm /N 100 /First 1014 /Length 2208 /Filter /FlateDecode >> stream xڽO7)tL.J*bpH9ŹDŽqyiŭ9hlgg+uP!fX\jD~@AY R8^@B(]+p*.ťK@!$S TDI9T8Ar.G2~TB\1Uj\[A'+g L-Qٯ9ìY6Ukf>FG(_s~.4:xQ'/X/i&uN| ] *cp \IAkW Jc*  DCa+(!SX(| i41FMҿJ\ T| U$VU󫨆Z&cX G+9X?j鿓`-ihK eRiYhr}j yzr͡ߨ24"CO3zQ~E5 ̔d/I~ ?D  rDWBFJȎa4hԮ0B=(;^ǒQ^ !~C _Á/0'p5t/}|.߿??7>eH^~x-O9b9% GJdϽ&\ˇp.|E|ëWO@5Q@b"uTl| 4$`ZH-Zy KBVƂ\*+rX%f>H !.A9FQF1AErEQQ>EC(0csUBזEe+UʂEe2WV/TQƩDn-;CCML(-hi@ 1Wa4Y׫N1jJ+)jĆ'azl$IS;6x >76r,Xqb[i j˗!ţc@P٭yb0@1A3Vԃ(tN R & ;6oAr(\U#;fEIF(<έ`z4/:(ans f+0}p&"hd ZeVVD&b$QiXC{h=Y6_˩J'! v*; Ie9<.5<!$GrS Ý1,MDêi1p׎YEip_3YPB<iyrZF6'AiB) !hX¦[P#7~0q3EqP _S4ee BRtBO#2/!W6e }cq[S !| " Bh+}羖L!le$Kʎ\ )NYz]:G'=W.`U:2VDNb}[j@ޙe!8L>"m X =tx!Ńb\Ґ-w@3~É)BaP'( m^€YEQ2eu!Co`PWOaC\wTmc! _5Ej ljL@jZ ?+xGL6/Ƶ]0TcOY1K)CfJVx3S;Ő)&xb4wP\;3&b1Km K%tG01aX*T#Q&3,mk'w9fXS!lrlۦBg8xDY^v==)hO)VGIa?%9leo2%w5ֻbz_C\;aX)D[-wa.g&1rd\].gKE{T)YNK'E9D-p6rfh(C}g=v΃UR1xcE$PH泯7;fu!6=0]owj!r3l^{( endstream endobj 4346 0 obj << /Length 113 /Filter /FlateDecode >> stream x332V0PP06S02U01SH1*24 (Bes< ͸=\ %E\N \. ц \.  33qzrrJi` endstream endobj 4350 0 obj << /Length 122 /Filter /FlateDecode >> stream x-ɱA($ \vTSHB $:@\#Q_TQUE&MG-nu8M [Yð,ΐV]'v=WN;S3uz3x:cE_ endstream endobj 4342 0 obj << /Type /ObjStm /N 100 /First 985 /Length 1984 /Filter /FlateDecode >> stream xYMo$ϯ1pX*~ ^opû:(c[-Z-Ǟnh鴐Md45`[l$z҂vR<JM$rhHX蹒 Dm@UtGWܦ=HJ R[ r$Ѡ)q(A8XP5 $!hK'midMxO%TCMo-dE=䚉EKȭ8rDK&6{oy+rdjrB=x*V0DujnлU_{ VyڝV77ꅼ Lxy3*N) @5[:(^iJ1F&*쯢{M+n9CN1Ƀ3`UoCE:]rRCEA(HA GS9+#D%@4Pd2ZtH +~U`.@ 4wElm%*ײc)4AURm ՜=bayb}_wafÿ7Wl_ܾݞ'eswwܪ" /^͛}叻(RbPt7(y@0ihe@n9QQRt+wD͓=Ӟ͒3(Lu#Pkžl}uov݅cu=}suw<ĻpaMyes(E&2g̓d*woyyx׌ŏc1p`qaXqa;+f|'خ %0&R T4(442|ZۤO<6\ce71_w[D Ut1xO;> stream xڜt.b۶mъm6vhFc۶ڨ]ݞs߸#c$/bJRuFQ3+#+ @ۊQ hfk r"PRjX'-J-=?@cWDd({X9|l\|6V+:8L-uKcgG +O)-ȐdP3v(ݭa@cnjold5Cʖsf /%;/So@cׇ̍?L.@3.0` A4x~M D+>7 7; Ց%&s&{+3-(Œfvv@{WV+hae˕#+ h7V4vu0X~eJou%Pr2JzC,& a0rs8Yx<tbl/R, e&o x🮔\A9 ')F)mѿ[篵h_m˄7t+#fy~f8'`r ih?j )c;+[dߚOlTYWc+Q{ DV.RV@3+WSK oZU\~d5 K+S{ _K@{" bofeo`;;{! y=A\A&G7W?P~M'Yo`Y70KYR+Y7b0Ff߈,F . o(x@\T~#Pt]7E@5#Pt]7E@uAz73v12r6uGW+[3?r_bWr'@&cgcS-1?X]C6o1u?[%VP젭9t0/:T~+c;*o _nzXZbj7(?^@?4@2? Tj? (slkG.6ߡ8AA;Knv&:?(r4ȧV:^p4vGi9X%²(8A'\ɬ~XG[?6 8/t7/1cGQA/B? orp]@*?\ff]- (!|mP̿S? *u?& U7g'o X7us76],@'ae?ĺ.Fq w mXG!s6EE5|R Z ghO5XVighc;'b,YfAhUTt#oD"Ha3 QFrq@yuH@Qw "ZPM6yfZ>WЭC]*@?D#'fb `NSR&؊w%D)zDQef>Ofegbr &I]IɅ&[艗i W-S 4D4O.î`Hײ czhJ70/ N [EڇԱ4U2j^4~;p8 ~~.oA[kZ Do^v*ݛ}n~+yI(h3LPyM8qM^h%J_7` pd8'ߓS&30ڏr+w()d@OSr&CG{ԔVSķl|ݠ#OY˱یNn$Sd+ȍg$d=׍P JW?HrǍy#KL0X:}Sg_"l^~2#*l~fY{4{"R/9SM5IC1zit~(&ݻAM}nIEn:.ٷgS8#j[)lhR97xrzbaaٍsj<7'lBUbVܳH`;baIz)Ȗc5YYs&>F$%hÿXi](^~K=n}Uzmȃ2mP.t~Nd8#2rsbtFz~Jc*"2 To .'%z?>)M#DžNȥ!ր&ו֋u/7͇$J$vP53=)O(WsDI kS_gg|iuvv?C5ًt },Ck |EBŁA-S8aFC: +OO>o-P^sjDfuE=#Io;Jq֫ avYY ag{~}aAj_D %]9\< ?`>}%6541 vO⓹ue;"e:hmm$]Yc(~*Nsz;'tvHƭQfQpЧVVz|݂7s{1 Bz4TO<;3J75::_ߝxr/vzbHH+94i-Yy6V\'g2YޤJGԚ {qQ^Z]Q4q4?|i䖍.{N>'0 2cg s22r΂Ep.ͩ/O\/m8`d8/Ie2R,._yGg&NޭXmk!ٵ}}5_W4}tB[D™y9D:Ap:J c6okñ[WEz t! 22Oi'[][Fa]7})z}]`]mPߍN*d^38&"ep8{`_}=ntaf T=$P[)nl'}"vdgyMwGp@kJ3 ԥPM1m]4݊{QwcpH.{*s>O:9 >OfUlxw3)]`J?_j*d<{%kgFr/V nk|}2%/0E,%jLzEQ#c>άp—хqWo `~5~y:xO"!+;Tl*LqW+x|wvr[|hiЛc.C52qQGv"'ԔfW_N%:ˏ[h9OZiw&Yi`a]Dl>\흹xgh[C_}%v36^fYy.z;yD ^xLZnj8v51ӈz glʩs |Lt(:C(pa&7S٧ɕ2 vMdB |lD&4u*kd̐Ջ/wc5hav}gDW3=2\gzlBrVN_Ӫt006Im?1*L**堑y=- )pXKQ8c:f<C WR" P G}%(S܃}WhyY` 7 G#lʪ< SX^ +8:hZWzU{ha86RI%#FK c >7)Tڸ{FW^H-Mn4QFdNotόQZsnݙKeM洈zE19sG7$ zr-Bbfjήow  TCEl[WXBd,Popnd;y,qe-V'oI0MFy_ы{d ϧ+9zl.}w=(DZkH,$519^ab7eN5 a"!$BʄGY_.ߦ_$Z*n |'b@"ƨ62@h^(+1 YK/w7oQ~t=p)>-џַŔʥGm *\X f} { -Zű&Wx;!kcαJX{] Q*?J45>& lәP @(ʱj f/i%b4 owQ=ES҅Wdy T}jtPXyٷR@ 8 ◥W n)p-ʸaI,4s E[ED떽q;n4 jd  q09>%q_Մޗᩙ7r-rqm{lKU=jR۔5C9?bpyJ񣕹ENHhp[s K2[<4U<3LywLdR]l?4&R)sqeMv|(SaS!z;*K f9`7ܗuиS+  &ək@k݉!)fɈNՔmS bI.OΎ!zkC04\=k,Qæi{y"~}ÛŚ⨣*W--lȲ8e%" BlIn<V I{5B/`+.G7(U."\֭xy^ 1g7oo6y8/hiĶɛW GHASZ[nb12GKECm(` 뮂Y{U'LdƵSTeݚq8ha2qvJ`pJM~atO җZ>A\O3թPJ3}̪9cfT%-0Cмd?;-Q܂,biv٦u@dXNGfI51[h.V.lSgë叅5 }ifcyd`X%">P; y~yXҙ7O _*:x6OluԆyͳC}ޮ1<TCs3T^.𕩂K_2h\31G{ |BO誀- "s{0XXySg&#R^sVDݥ0L%1l`F̧9UUިdB';܏%ڒ[7=ش`WzNP/GXj|wx5j"ggC.ӨVUɾlW@3C6e(8("y^ 0tY4M,J x\Krz3{@>C XMUgA #q,wȮ{[ΊYܻ:hu>3aǩ]YA9tQdelY]Í#vL^wgcvYDdKƗ?SGV܇(k =dE ﶳ% )g3z=>t/Y; 7*Pfi#o>Z0is*l۷ỷ5ilQvhMjF1f1dUyq u{'Pd8IqӜeߛ Rm_rHa!+]&yu7'ZrD["Ώ /\L],ֻ,iܢ,z硖HelTq8*zEm=mx.^Gc:f;Ϸp<,rmw1{eYשX ڒcwrY&>Q]u%&{bw( q W&ݐ'@֡ g|tzҦhڂIw',۞A>#pGyUm\\XBġrFoR`ͷJe73D-\BZ/O7,efLwP^rX[wU孃7PbCL,E1fN}8"뛅6I"6ji1=G|HA\u)J.}kcfHz*@v 1e:~jYࠬ-йk8%j⚱v"KAτ25Cm'8v"$1 cx7dIu00G;t=j5VYȞ zӏ6?5v 2sݻ–4[j޺q+6-!ƿ"&tGUx s/^O%ڈ"}ye,78R0i nFJV.w#EY|ԉ6| a=o'GPc@껈;ˏSS$i6vx O7hˉ<)MH;Z|>$OaW~MڸhKΑ>9^)`6W_㺬+ P0sco)[z HoM++sC)=Kɘ@0!ب5Dp䡹HdNp21Xy\bT~!_9H@wƧGL9?fR,[P2wՑE{\cLr V 2%z&;{h ,]@?Rbo0=MJ4+g`vEl,8>;T}3hW}WφizVm]YS]ٯKJXB<~NbXF/t \T b~6(Q+m洇zP2brI|}L=TҮ6dIIca뾺*1p1mbY g'Bl+yUK6Ǭ̕*|5=Э1`=7l.$%[H $^t}0Q#aQ;4^2ny&-BE I &IK'y2cu}=R!~Hh?qENoM&F>l'>D v[ `VAP+OF)YdZ&~L|XQ_ոb5Q G ~CemsҔ_Jz$%NHF80)G {vwwѷPMs='[q䝊HcX~`gFXp˘qtb˓fGw:LD#r1u;]KxBb+YS/(`*OEc\!^lB^5Oc2E>pS|}>cRW츺N8`Qkzmxd$I2HxC-6" 0[wE<GV67!Т :˃Hrj\=_8&3{Ӂ"GEѹ*,J1Xe'[j~xD'scyAAZHZs5ŦzseAGWiV7ehG赪oD)Y |I5FpHYXhd"sې/yvBp洲nM:cv*7h=9KW*?2PliaW\Juh4ӭ8Pi)B[G-Zk1"XP֩E`6df4;}^:S5&C~ngBbO1$uԀuv6-/*Q4/U;Dԭ#/שqO}m3:96*;͓I90p ``1 %4X- Z?)ǾzkSkY}I}r^.@2epٶZo8?{s1&0oxEgO.b0$rN{f=z=U;bì W%TB<Oum3)/ * ׯ{ܐɶJoNAV.)WŠr/Ѓ}mI],3%Twɬ΁ eqql!8WAC`q~-bMM_Q1D{z!_q*g` p>8Op gP7 (`ͅ&BK"q?HipAR%4b_wc/˥G W|6ZKDmye|ѳw7Wܑ&I:1RவE\T0u3##au2;}R<N Q 9(1D8"y{JIJoCկT>&+'7M \iWvCϨkkXYǏG'$*^lm-y ;fuZҩbaJ߀Vqǜ+&?Y kõ#)?)[%9W%qaC۱N WG1/ U}7BSփ.{蓇)ײZ3r>kF@q*A3ԝFx׊悘 :Ql-N|<ÏKp% (r2AZ-N]@:y4)~lQ!5ѹζ15$uӔ ̑#lE&cRy+ 9gh%FJ!~)E +=Wo[M$X4a\q$7^8)M*gdYNɐ&o.CE*c!W V]8}aj_ Y7&jVV'ϻI]>Ar:\2n"T,:6Ua1Ex>F(v>ٴoln AΪ֛x#y m;[&\ja}0~TNk`Ga3۞~PH FX9]?l8IxURRQX+x_+pm,QEly_L1r6Ⰼ}Y2elE+(Fxb%v^>pk4RMѯB{!! yoIy}{CRba복3`83f99]!ѡ5a5%lvjvJN@Cy3Z}0}9n@ >ඊX/ZNCW6D>̳Wq~ʧ9ELK5TH `wA[`1قCU%LhbJeFbtoЩm7G8:T9HCU?p/+f(U,\4W>{aZ{t5N6 E-c<@#GP{~n8;cnq"~5ޡ%# qO W#[Y|PB)3~E r=|AYYWO 3I,3!#|q8bj1%Ue/dl5"$CL]Dž?L/X0. }ZuogIۻ:N621e/Y!jiBmcv VEg?o?.j}6YlSr&YvNQ,g'?؅λhWJB[9-[~r@?ir[k۟H<+!ʮ%'qaq,QDx!^7ߋgm}>Z~Hv2~W]&jr"/Sk,3C 12Ϸ.k*BSuk0BÏK/MXd)Hҥ\.F8>n/|NY.݁'HYsg"Ȭ;kٽB8KA{ER>& CP!Sք$'+ .x;[4hd>Ԫ-^WIEv;ٖZ \ #UZ`}ps/v(}a>; @ҔDJfTYe|PFWf%bΫic}3k WèO-F<]^\N  I_dBӞSEǝ8LAGF|&+.8OY0`6'0EK)+ Q`7A4h~WWZLbdvMC/-%՟7xfAYo%YdcnJ!1Ѵ%qADS lt) מ/hʳ"uEYFJR>?:›lZIBDeãC9W7;Q2'ȧFnӓ[O<ûhטM"yd^%xnT& S|5}ifsNEWi VsYsף U}_w"i:qg5VOHOq3gC~`|j42vZ!@WpwDKQjq|͛F_wi] pB (փP~8@3{B0+폺hFHpL8fBt|h JJ)jRfRϯdA}?oqjܬ 7a `q#4-a;W;gղc-9Yyr+s{47ؒy Z}NT"cwG&Ɣlٝ7xbn5kap溋vC@2k 8ꦎ5`4>DV'Fqw9-|%F\4\BU\,~N:5Kc?vv sr4P mN܊~8t=֋Ρ]Q{ 5G[88t:_ݠY*wif&3{-RUn Y194HQ)59t;$MDݦ̧l_|%ѽE&d-f9pӁX|=Q2oL+*k=#Qw.Aw#k8^e9s f!(dY|ڿ dɕ"06!̆ä,PZlZV~*򠽄,￰Voې*̥٧u*a= 4v,8h=VcFNDS^S}l9b@ti;zy:\lZs?Ms[ ,.|{(FX".jmq[ "n޿f$M)v+`2Z\{Q{T;qMwh`89< с ({[:sOJK_tpy6U-LemD`В ~]FkE^zc(֮~D_/!ȥ\춵gna3_5ztSɛ/CVaN; Ef\?~qQ1ٳLSR>g+ytl!]ď>':M02DD-S*BhvB%-C}tlS n3]+׸T֪dڟD{q8|R/yt&Ie; y 3 AX`TSrB6B~?U$}:BZM@Gj@1g\A]oFvySIQr~O[(#By ҧz5sę،fK9/r= =3Li?x5XYpi}O%F}v3-UMnId@?{+$LI3!&T|+z¿MG&j :Jݴ =Hr:z3ŚuEKtjK5gmΎn :R˼ H~s٨-0S? 1?F›UWlGQutaZD=!ݴÉ8{0SҶ,Qb!wVs#pQ2ߺyt:.V'?͆F9&hbuU݉Kk3/ tBFŪ3 y̘ƘYڊ &HI:vByʭ; |gr93ߵ6Č&)B͛癦TqGz_ym;vp 忹$cZ8ɿ :xRJD7: Nʞ (-M12'Y6 #;vR$]I2]F)|.$YmIL1 [Qd:;5^+%I{ zo<P{V/&ܲm?W|nhLffFPhyR֯"q֔:2?7N?,U%cX "(8K7Oi0w]˩  xf "[ӽ Nj%,TDZ%~o/5jHТ&q^,vz4K鄱v â^o_"3n-(`D*448lrvc%{;dLrψLF<1`Z j;ZoK"z.-\:O~F2.5ʘ>~$ek )i B L/F4S\çOk RiFM|Ht·d]!lMq\۳~T|{a&y?zx;;rf5\ݹê4"!F&U#'4vcHuPC_(w5O90p:t ?Q iOVNv}r'coRIԟT`qv`IݧXzk )){o$#Xs{jJ(µ *Mn@:'dgklpWJj# &PJJ]]6pr5/l a=d06cqlA3w^I=HѐbuxnDF.Ӌ{nvݮؕ8LE<)< ԛ1{XspP t$P"?6y<^‰l: ;xVZT-wcC{*!0A@fg<+{[/E$7@چchEB ̂!g`4cMȽaI~*4 Cd 21VPs{rp ~*/,%;riˑHݘ,[z$!-`ڌt lBZ#t;R"A6 6x`W<]kp S*Wu:Is 3*AHdN(d1,b.n:g*[Kgyw_!v4=eu Y*yk(WgwO&95ѻ_gxcf>;XbrD-4/y4`$I8%71Ll0դH/k`y$i "B38#i8 ,i|M9@ubT⓮~c >2j;@_;ΙC9HW#rj$k4CxxQxv.i>u1ZNYm -dq U(qWT14= Йt?E1ڎ:4 TS!ʒ&02EG3j XF!y?_G ]xz\}=ünY jg&w~d5 z_}hprg5^Դ*l5;mWpjhsuRKb /!Sj4åZ&/{ͽQA_|t6q\l6c ]*`1mrYuG>yǺaf}Z3β=aĚkp&P)/4QzHpnYuWe-]ºp;&ܔ~@hy&R5/U2-ew2ќ S~fڗEt_ny ғvx4]C K[Q8qS3?tkg!@Pj(K)Z8Ow_>,[f@+c] zRsQ^Y_ku`K3Ii7E^z43;+z ׬ZyٽVz.__4㳇JzBWG aS1^9J2ʹ.1]C)`LNUAI'ŝ E0rM,7H̢MY.Y@ lqҝ8jT3hځq*6^:|k>>˫ | 5ƚo%V8~<^cx^߉'2)=ϛ-jo:/nA#lbpPA&l`1d[S*~՜aY!7멞(OvA K(0x^RL/ B+}Ly)f  !B| Eڰ Ⱥ osm}崃>\cQo exT#:~ ´ =$]֡!~4~*sAسv$qҿE@gSU6BщMN[ J W{pzM}mkI*Vv MKu5*Q2l+"a1ucf{{3M0Th8[p]tNʚh!)s% 7n$:l*3h z1#aSH+~F$F;fA'7^ ndPHUEJ:ա4ޯl<=0vr*zfNjp(l(;]ϙRWQmblƾxD7S S_R)/\q#eܗ5^Q%Д#ӈk$InsdR;Q-: ?+f‡Ke.)C$?, 8k%ɘXN{s[v w^y%(G\"D$'/yo8.B@NU-sJf۳u:3~|9l3T˅[YE]U}:UI8:hထXo:;Lu@0Dé~[Ew\dgs866X=$mF(ڵ0(c[ubʛ`4dQ̡'LB 3"h&p?ShSD;tK_ife ꞟם MZi.'th"<r$G*wDE-^URN!0uV~NFH_0?b}pi2;Нpښf `[>,Xl(y3uS6jHϪ@OY5gy0TSq!yz#5MN\֋9sۤp}SO!&3LEElu| dJE)ޜboO [?CA>ԗd[G== {=&KtjT J|ܔH#>a/e'L<87%u"F JXMCYP;`yi xgx4-Z҅hGV$&ršK375 O֐mZ;2aT+ΎV~U]cu J7.n_ETsWRc nܵyFl|x@xg(&_L}~ WI=bS)կ҇[ur+ވ9wG^y~pʝ}&ޒg !a3pN IW"((?Qw#ln Kt-Aǻ5PqO9VMpvcB#-,95ƛZcG).Iy(^B-1ϨD:B \zI%/`&1+(U?}EK}@4/F3ROv}/~gёOk4m(yo =my芏̞sr=*pwRCɈFGp8*[Ӳ5ʼnxf;:V]&aW{;WjVg=@SѢe'W^aFSʭcBn*pMG*Fʖř#ZiUKF[B!C#+˵T&c@Ws? t*R_mC/`Dۻ"}J+_^IHu36AݍNTpvQ0O_K]TQq6ݔ ug铎 Ԙf)߆8i ERro'끕(vtkDAs"m~ϭ0ȸC\%--xP/{W pgІԓ%њ+?C쁯W+6R㳘 ф{azw) aK6)*ӝӏUM Ss25-lw[ pN7Tc&QtTq//MO8NIت]h!Zm`eS*uմ Qa.;::k/P3<Esk}Ut/Q̆6yz;Y bÿLo㣲@=C!U-ōA$ꨨoL]CyϢ58X!믜tXH'%̞yԍt1j뺸Ϣ)!|9Ǝp AyEt5^n 8!9#N;M`o cN5ጧ"!5ׁ C8okyq ^Yuzjc zQRF2C}[IkCxxzk{aCm'hO@o:p.IOS@Lo~jW~FNji`m/b[;Uryu~b9]1Z;l֎%ƍ_jjV 7q[/%ٸ`QaI _ɳŒy@eF-N Ū=cfukWtgmZ Ab>Jy˳* "LfZKlhN!t3{>zqrOJ%b`O&K7"wljg<\CL00EZN]ѯIWr$wE^Ȳ<]*n =@BT zXPx?]ݯR=u*N>x/+A#%aTO'E&m#gOTRmk13> 1(M./U|0"2Z\Vkћ^|0RZD,cF;¬nD ]&= ?do! 4D2'dЧϟoK 9d֊Rih.29 wV( :wQTycĶޣ9_ٗvPMO& (8:N] endstream endobj 4367 0 obj << /Length1 1409 /Length2 6329 /Length3 0 /Length 7292 /Filter /FlateDecode >> stream xڍwT]6R"!"(3twwR03H4(%t(!*t|Yk콯\׽ag+o ^P@A> Pq'a70\?(()1X6x @" Q   D$J`w@C$  EJȻBQ0c!`!bQSAJ{xx]| } 0(wjdg4>v# ;`xQP@hl#0T"`߀?UOU!W2A"p/`stU00 vA#`w0lj P A4r5#U1+P8Mr՟ `݋:p-{j GH~c8T]"DńP7+rcgA"{P?=CC#i@;:$uCG<XϿVX!.^b~sE5CCM?#+ xPH ]U#WŮ=!pYL.o[_)?_U_FXnXa~] Ŋ}(!+ (؋{XK~>8M`g#P$W}ݕ﷉%?m P(loPO($"ĩIq<ʈN걙HWyz10+sJSq=Z:/C^5k >G&ɛp&+0Kzq(:ez }A]"ҪYUE(nl;`"OWgK):4OH=*)f({5܃Vb(%WS쾙NczKnӮt+Fgqyw.gbM}4h9C_ckI8Bt^ϕar ]H3EỾ'/ʖbCq[J\Vcsɚ9 0x(j$S4#%RPZa|kBCov)(x UBoz:HZuo碥V+ЯܻUGʧ K'1|-ʧzpcpJtrKOi!ZqIKO77q:$:oz%M:DzIqe>߿!Ӓ!*>7lliɣiY\ =Zy+G{k)Y@zV(jo7ZK_|t`˔ݚa}Ii_]{,p2^/wTкq\O wv=u^(|'Ί5O"ء&aȶ9S%צ11Wy!){ױɭTG:Ɛ<~T ޱ I+lҚEd}o ndMK25s=OP5|:|s}hCD`ҡ!k¥[T3g}#)k[5HDYfi^̠GӇ,Fʇ]NoSs#~V5jn' -'Bkl#d,K|ihh~^F6rQĶGIsy8e[M'a){n' ~T\UbfI^w2uNIV-7g,LUPtE̯G#}qnT]owo 3Z먗%Bހ J2*63AΘn+ׄZ|1*]xЩWAgV-B4FpQ@M@A ڬF)sQ%D O}8bvQp k۩p?80c rj8]DdF"BYF|-Yi˫ ́:IAr|⸒6ީx'sh/鶐DERW_~:mPӼ b;3ư-« ~G%d-He{f>:*壽:C{:i\m*q./*(^V4rtX>MǜMň?g>lDk/3"LE{${!J#3A")0cpbNJDA7e{/i+oa@:o!ȷ9a$Yw\b4-܆@m…sTk󰪲ǚ@ %9񨻩 9Qtܻ/z#cP^Q+#/˕?eJ4= Xc3c~dK*U$X-j %r8dʠkSzóG?>j^{Q~m͎|ލnN@d/wɽ>B1UvH;FIlÀM/[I_B&7/+Ix|rϔcQ%=/.pVdmuk˄V?ZBe?'iޚ QUͩ'o$Oߤen;8pD &fI 3+?R*.Ɂ cYdًGY =9lbn-&xq$OZ`,ߋFo0)8y% ^B+i|nc~I(T~1:; ,1=J "M.V?X(&ьsg.~=ǓXxoʱEIn#3pRLQxc)i'P oKsBER2}Ony [F"ۍe2v}`:5AIOQGHӢavwUV|(Ƣ3l~a)徚>!1wcY%)˂W˾̭J iL7b[S>\Ifj`͑#%ÐsdJٞ$e4_#Yʡ a&W~[Bap>X~+DT_|u{o[9F+Ll2n|]k J8Y77_ڳ jSje9OJ嘮J0s E/+Ҟ]u?% sRZ }uEU Nç^J;YF/}=(m˻a`/˧e'8 /DZ%x?!ang2fԓ4ig[aG>-ltvp4Yiu)Rt`LyѓTz7=;j*moH~;^.Wy2%S.P# #?e 9b mObx=nk2E\LQaRBڃFiW2{8-.XL|E[Ѣ_gO?@IyɠuJ*:QXs(G!z>cCc8HTqX,kB_Kk1 ,5mMgE]yN1+4Ҿh U/Хq-Zʤ4x ]n oIt cop@Li]ㄳAnO}Ǐdu moA hl IHLMXT&q'gWO͚rˆ4Uw'E߇`<)?'=@;6v8$L#{ZK/ d#p5gɝ ~6ԑ{Oz<-"1 uM&Rlߟ+X7E[{Ci%P:6~9vUҦlF9j޳r S{xdk@@8ܱumWOQ^d͏) ? %&Z= ֞D3 rȾ5P.![0ti?5 ǻiە4}٤zEF\-]]S };"ԍb.F2>m'\SKFšW/M ٖ.Ug%_SDU( a½N ]L8gr*ڎT"l#`)ɹ"$kfwfFJ<p7h~K('BvHWAG/eboŸ΀6{7"Y0m!t+d#w $㢁|߾ ɓ_uyEq +M $_SR*xmAQ3MFq-j`i_+ ó j=ZJ;FقM?qo(9tk-U,b]{VvH&3^4=zYw6Y:Ӹ-/BUd? ~Z<Љw߷xZO[tWI&Hx8iNZ[}3pd]1giYT=])dаW!R`'1 u/\y<(=-&KF?er|Qe&zTqdRC"7\!4t+[+y;@0"՘64JYt%1Dn.^(!"͋ǎr<A]E&."}",g;K@LyP /MUv;h\۰9s2ҋ xI珃o?Oߴ0|!mt;/ ,vkgtu!oWhn)2N2(i ,uJo&,SzJpf,vRVPTiV"[.s$DTg|MTf_M3YmDbf@S]CЯ(|Z|.,ds9TcZUMp^s'~o][Dt>Q -<1hn{!\|2}DJe"=eQl=+N8瞲hʚB{%' endstream endobj 4369 0 obj << /Length1 1504 /Length2 7662 /Length3 0 /Length 8668 /Filter /FlateDecode >> stream xڍtT[.  C ]CwHw(=33 4H%!!Ҡ()"|swZY7ykϻZ\T GryOܼ|@ ˌ 4pȻ@-w6K]:Pqs !1//W?1; P PWl<fc?K+ up%x#àH`E"xx<<<-].6RluC!_?̸=[.a``(. 6>Qh:Ap:Ul #,^0 h*q#=K8W+.`iusK6_\.0'++E_eNYG8:BHW_)\csp/` C9an' ܙ@A^a~>*21qB8H@`л?lWKw(@``$ jc] . x{=Ww ^_m9yUu?''p\|H[%.xN}F@;tX6i T -r^A^-)77-a^܉ y7ꈻ1w!ЪC!07>AZ ,N\ n^?v т!$Ǯk`pm/|;]qY 5лqwp0k..^wW>@=+ G Rw_,* 2F:<@APxWox'&?])?])_tn..w|7 ` ꠖJY*Q{)gF|\fX oqJs %3v 97_f}VkjN蔾YNߞNfoD6L+pAѢ|4ĦGR5L\$ܢ0CZ`gYdկ&xBΒr%$_4}`pMj>=$Y.ϕy6Oo dҵ~rW R\a9͹"_7ji{phbzLQ#stv?_ njU;+VZr6"Y5_~%k$;s͢Յ;#y0C503 vh@*ٛ&ѭe ď9+ )a$L+hDb37ptY!DBGp_ߚI~#-?RX6`Zpr7tnnfd Kl5}\>hO~_ؤLHY1!1܎R+ <%_KG]4Z }"!hK=ġoDyYt+A3{pTb')#68Qz[kpkaW?Gz_XYk3bi+ Gq%ui; T1CځEj|6 WWEuiЦHY%-b!juW݊jAo6 g14eȱEd5"\P/\J43ַ4g<DW+8C5@ߎ݆ j#|aQ! e#4td<ǀ2Ì멲iuzdrigjfNݧo@،b"ݯd}>vcܪ:Q?گHB:W:S ajzGtT|Io>/\t?TX̙d+(kc:&#$F'q&%1d2uϠӜk1c)ɤg>UEP}#'ŪW A;'sx!Q;pJB鷷)?4<[ #<4U});U#Bv?aR6{7sa!Tl9QɁy/.FfRN¤z 'KW$ԙE;<jIЀZWDg@0ƛ1eG[%bAhid}Mq fp`TAxn e%XlOM 1܉fU8ѐyue|j Y Mgn#ƜnX=I|1EHĴzKV!O_٥t$HsP彿d!78Qa.pB#Flby8@a;?}2Ay)\~&:SI:cg!lLwsƺB% qȓ@o6X]__Z$Ṳgn#hNZ#֣F$qftvTl͜'pHIVšw7yr(C-rv^1fRTh c 16ꑫ(UnqN/H:/h#]_$aĨZvǜ:XQʮ\VY,+Ÿc%_6;98(z:]ĕ4xzU&4 FM,Cua|5&zy$c7fwdg]cMggTN|ҍysJ4zK>utr9=*61W\P&c@݋I,B#kD#qdgߙVfXCëka<^֦[RgfkqG/.;Q֟d[`tlMJwnzOz[0"5+}+ez%%k]͌qM-euVh|@J=%ØI]/"̔T_p x/̓V)8_t=.8~YۥNV?ko,9%qX-=C?fAޭGy,>kg]sr#1kEf=>&/+%=*{֎ڵQE+C\r]pL ‹5GMU:},)ǁ}1zIMÒm+4uU0 f{Jw0(,i q ߬QՈ] - ]}>} .WÕ&,7CJSSD炻 XPj*R_}Z}!q3j_u+%yev?K I:$@Oc|m%:jγU WM9i-a% lH@Oj՘WheHaFbBODY-;dvle ޜȤAX(ntS9Nt>w ^/t,^냊(Nho-:M\#p-'k mBJRv&Nj?})qwJj)^(sryd{$䧌[m%'bDaxͪ- >e,eڒ,7&X7y7|zRMފXf¼}:DKa˖upCxRaJSǫI /Nů_ .{UF~c^jr-r#iaћT٤a~_/2yeqDtUbzL+,-2=>62GE|4a!VBc}as`Q lӅV)[I@+>(:1 [vKLfk'7Dι6Q@ȁB\ :g0/MUΉqX+Mwq}}c疠ݍhڥb fTj>ChSx&2X{lEA\Tjr9;t_3nmT; W""df YdP'{=|2bt݇iHea*lm[q$doY1^{Q%G: K3Irp/׿*-T6;Ayz0Z"N@f1;HJ+\]if\z1?K$t+;=`X0=$CLVJWF/z BɤLUn Hk{/ZQ~6oy2a?G4m,9Nja~D-G^Vȭ8'pd<6gҼw( pӢ !;נ*փ!yz2dnIm, L!r&/ ޙ.uncNKT>Iga[ON \R<* ӼЩ-=~ՐRʛO0.vDG~$`yՀ%э)BbA@X*M3"k1(@[_1Bz@lt>b*`f{2'W6*ۑU𙀀sSZ5^-ss nM2Qѩp+!V[?3%(XB{m?p a} kxHmyYw(|{ݍ\}\(s**XKAJ=ݞyZI,W<֎xz>>oO 7k DF )͆;iL2م}DRP(L?("w3KB'C9y+s-j7Ž񥤃P-ƓßZNeV\Q/n{t_k+w=yΚptZ?D#MuBPAFBiw QoDm)Ғh$8! qPxxlv# H{؎3&~s-ųD_ hqoy^8ǚW}DhGV%9tSQwNk<ǡ€{K%ajK<}AW}sr\>F^m2%CX1bƌLQxuV'+OzۮFƩ5*v ߇ pijZRd؁uS g ~qu/^g%%nK޽S`yٲ5LQlWHWEh- }Gvely+cOYe^8ȟۨf-LB{m "(KA+52?''G98`v2ө&mU.ҤB^Y*ĦVMFxb;OϞWE%O&:1;=ć+/MsUrC|YY0| TSu5LI9`K`җ&>1jTTk׾9SMݽcN m1j6ikeU^Z=qFq}5 8S(bĸ(ld|;8E 7y O#o/Z3Jvacc|Gǘtq3&;:Eh+COz,r|: JA \*'G],zܢD$3! *yNX#_1}|DW΂ddƩ<4N]T4VͶ.FP>Nq~tJyhp;_<<&{S^% }`j+KvˍΡJ씵\zV70_%&o+,/B[,fёg!Yx&Cs-R6vrV6oM*Mc/^hp0]B p@Pw R# QfǐtyPT.aDezZ&Z/ 6SqJ4!RE릂@J- Ѷi?0ws>n3$*;h7.>ʹ/76!d&]5h(2T+|P\9y`=ߔ c(d6&nKںZ;e3Zjuok]+Yid ;#]gOөJ?G lTKNjM|TfԊᙋ̅|C$Vj7naF&BH?j1?<:( )(z2y*lb>->?sb\T;0u~ixp${֦ 6d/X\S@Vrb$dCVm ţLFtu KE _[hT^# Ym}QMautaXҾg|Cب΀!spkЇs۹@RxŅN; 2MwHkp%P#eo9=FEfd 60\zX|r$Ѡ|o^nO 7oUJϱA8+'%"(c4掤[!Z׬~$3TgU6KKt/x4rxjD$e vauZ_p7VI!*ꓦȣLwWceR?M׋3esn+wLNie ̈́ FǤm,Cܻ/!n}@SZ=͗!VL> J`Nsӿ7 8$0*L}K Ep4kV3?Y"+EpHme (*u\U<멜I|[F&qU{15N Ġ>$MLz>!-k=emtoz'T}툋=@ V48跇!@=KCOVv3mt~||utXo0 pLZ9Uso@zğ<&nQՉ)ALP60L 8XBc`Œ>Lf WN# 3"Js2"=Rn|W3z K(=gt -,41*-4 endstream endobj 4371 0 obj << /Length1 1386 /Length2 6039 /Length3 0 /Length 6990 /Filter /FlateDecode >> stream xڍxTSۺ5Ҥ#H7 & wAjHB$t^7J](]zQA^x}kk͹d30T`($F$[ PT!4c$f04 T,PD@4HBRQU C!ahN% III(<0 8ܰ!`0H#K {{{ B('y^7 0a^0(=hB$g8/1 C!H(0Ðul$W?ѿ#p #H/ Fa^`8n PW2 cBh8׌¿`Y UA4ɯT0v}+{GBt6Ex´T`&ۜ`PJ\\ =| ¿ ~;31`pG 0@tsEps#Ik9ƞ`0( 7 iݷ43(@PJ@ 1@?X-# W}e?#^?s顰̅xMtk;_YWwGo?_v#| `UjPs_ՅAn€jPB:a-+Vp /e77 3@0( |XA\w4]0YW AAMDL`|~ ,Da!쌁GɯؙhW98rLV{[0 B2?Ȅ8UbP欁gՈ" zX]tQeg: MqDmLПg'Dl* XG.d44Zxzl.˞#wN+-n"7Z^w D8N$Ytfom%7k2SiCu&'NwiW`O4(4zgGl)ð {x1)QMmX㸅ȣc7RՙݵwۍF=UsRպ\RfAd'dPYcBA{hۊQK,Uw ^4mu gxš? D?|p{jn+Aݥң"ę7Ej:"v"7[Q$[>S 7;<Qdnef&NJ[DVҡ5r=gUw8(BJ3{9Πsuwo!!|_mTEQkWM%i݈{1:O;̴LVAOE;747LE?!һ$}MaR4͕zWd'~ 3C?~ՖSv[&-Nn䃼@jie5{左[F׽Ts UIȧFr):]JZY4%P!M?WșhϏ$ءaSzGQ4cQ˚]WV?X[t8 4"Se =y<#0lZp\7.E{:pU"U^hzzIǶHaITX>oxYPb'yq)F~Oi7&lT?ˮge(l~90qV9]\|>\*Zdxv]W}[?+gM)e Pjo}q}G.Aj`{ƴ5=G3WC*IDzZ3+W- u˳m7fHqw0LgJ+hR7RI[<]6C3WILggdgltyͱJR%5j0[0r'm>8i(s>{meǏlp|in|;ԙvgn]I0S? !0j)n-R}E:/!#G㨛U9:o۴?5f>b?^\sNMܥb=!ڌ8wnc\6΂'2,Uϼr`}Ʀk^%]q[9NJ [x;N&"- 5z.6B<{5B޾K~'\}BЄeG4lz}]g$-!JXo*T2.?`gl`)V !d~oѣnW?wݑH ]@ O7}oz]y)1X R|[727r4UE]zaEi-U'U7yYhc-b0kx'8tx.Dѳkx%{@! f njuɁby蕋Iv|Ho J8 3$%ͽl˾&wIbpa[rfR cG(]S6!bs~P^Ξ}<ѐ&A$㰓[v²s&>'+Su oR!Oωm") gK[A!ţըC~moC| [P輱:Rǯ.n"cd67wK6Ù_'Sp|,F|a.2))9 \++ĺ| ,"bBnUhME3ƢQ/~;XT悔 MqwQ,;[П!%7QM9J0XHtvdK.8JpS\dYiہQļ J)N|[!=͚QbY%F~=Q?cґF՛^gl᦭*Ҫd_-Ei;·'Mc]L]ecgz z 6R kSHXܕj^TQ J̐e4>c V/cbje`rbqؙaΌ O`kn_EkV2BDKW i7Y͎rK%ȑ/ɷkhԵW{|Czn,)v_-vwı{ e yѼ5OR d;, ]kA\8]vn>&אY8Ca"r7q֚啢s;<5 Ll@.Or%Ռǣ==+䂓6sS/n2~ }URڈV0fo0pj22fm˨@.g^pdt,Pb쎆DY0g+*mռ?sngS~)nFXN`fLe鳨N}t2m `^uyu'cS]0 `%O)Ĕ J(RK0)a䫌  "MO-5Y@+횃-aF $O8fh1*N>niȩ.38Ep:Z=g\P_kn+:Xh߄oqʑxXv:#-"]SY 4{r#}1E(BuY0ՊcyOB4/rky8H»rCo 27n'EPf^X|;8Ԃ&Q`YKFY4@F3nfyXܤE)b /c=u1r5|!*x]m:1LJukgsC:!a\ ݅xVfO^z3z:G/NT+t kNQg7ʯ62OWNm7w|PlU((?=$F_d2R^_EU\UE"||wp_*IA؅ӊ)AĨq\ݱD?jTI?"+!r S ;/B،1ПKfv#{POlduk"'r OP5KֺAyY9XbiD*NQz)hrM3Sv{COEW=U#sSc/$.gK!Aj Cb%\cV 1B&m.T 2@"fUR_B>kqQy'E w؋,%t=/齗AA]ޣߑRFɓfab<Șp[Ci$q6qnyQ 7(%CYFXfr9bR3ȓPW@яPHVrJU͋7p,lk_*Oh}'yIk|N-LKR}şua sjR8Ė8w_noUmNf S`{*js,W|ƩI)i"flvX=5S]j}1w,oPN5b* ]*"KzKM%)։u.MCI.LDb#P3pAk˪kSE]u.z_|>M`qX>u"9=zڳaz s}%p^5`,hoN~Jxd~;B jwgTFCVclSd,iRоTsIXa-s*:EG-t>ğJX"[ss=d_SK hǧ'y~{j2K` ÍexlTI&yʞZԁ~᪸ nUmV}BWQ9MD`Ͼqn /ο`i$TעKr3ݬk-=mxA] Hb`#b\ ^y)Dgw06|bNmP`f&2E%{ E{S0d3)Fy!Pש݆mO/O&h@*-.>͍$lmKPYg5PCk-Ǧ *\Z&_&FLX?o-X=8~8 .+"=`Yδߜ7W@Ce+37q㼮Tw;?Fz0| /|;ܘ:o) Ds =K-a鴨\gWE > stream xuSyQa"AXHx\dDg"B+1+|&WY#]AĆ#t rt&TA>Z4s:¢gBvP#X4L,SB ]3i̜!>@͝[q?,fδ6Ptw'alPXp+c62@gH4Lx`Ѹp;џb B;E`B !@5|SGa5 V ku^(o>H0fn_T06x)"o1WB;Blľ  îWALd3Ep?5wO-47˝dq\xӽsiiWsYw! 10uL 2)5,fμ87 `px.1"`P @7C0sN0aB0 Q̯4xf.=eςAp+P/AIg'ϐc0nYXm,Zn+t^fD6r)m`9o9L{c" j湥i0=gCT~Ф5EkcϝWFWO;T&#񺓛Qz|%1͏(u#%[҅S.x^Ѡ[ꨂJvU}E*&6޼d(۴dzt̬]ӣ뫻5S^ّX}Dkm60dx0t~zli^Kɚv󶞆{k'֩#%ILf=?x$6wjVurhu(237k<]iu4Mтָ'" ^&?S^PZo#fn=q-ޞ'IS 6Ɖg'v5+:+E-%F#/7삯O$1w_H\W8PAݓҨ@BT9>2hZJ?U7[qf*L&\꺪#oXl-Aih\Fѹw)}ʭDءx5{b 2+: M%w:~uxe[ؤ=j*/ާ z:V]q[e"Y)sa@&YDtd[~Lwp[:eMY1uX|ƹڪ~9qluL,a$+o[{$mr>[4|x~p7>Qi\XZT< 0\8e@<2}llDUޭ\Q=D-)p#1ve9k|U\3)J)}AؾގWuЉ<گ4kli3[}!FW7=81&A[%E R9etI犓%?Hd)g֍{}:drވ>~s@ҞhReQ? {#nq69WxKKԇn7r겜p=*VmI.xu$ #c|?M>ՙe:Y`{Yt2C eͺiۍ{6i8U捞5 K֭^]%+ ڍ#VE\~E"Pk~%lLs+ęyoj UVHF`iͶ8QO 6kKZ$M sSC] ąhv~B1Ja:`:>LcKRa-4&w([nR(UK}5*a㧬'R4>o R:`4V̷(2語rnxjo \s͓T҅ اPPhy`#qRãvEjA fR[SiNuC%eNy՝թsG9޷h{cdE>!Gm,)hi|-M7Q21dՈDZêhEm 쩒\h endstream endobj 4375 0 obj << /Length1 1626 /Length2 14258 /Length3 0 /Length 15096 /Filter /FlateDecode >> stream xڭctf]-۶m6$Ol;N*VŬVFżyO?5}Z$j "I{WFf^bE<H%瀣sM\Zsbq1++1 3ʕZCU$zhiOLupػ~vT]@[1lbKfj 4#]4Ķ^9؛)ͅ+ # 48'v8]\މ.Ė&_=pu ڛٺKn/@_v_`..f@GW⯬jeOnퟒ u5ڻ<]e 68ښx}  7!'vX8\\|;U'V׿e.[ F8֯f_-pL̊1 ns8A s{[/bsWJb;Hz96CK*} CĞ!'qmhElN%"_032[tz̕fV&_\l |30378؛w_T <p{9~a_(80> , l,_{ '!ZIU73˿_ [ {3FkSmc<fpKf|YXyz,aeŅ=; _ܹA4ueW͛;2,j6ijwj) 6{(Wq;):8HҘIR >v7T)V]Fiًy@Q.ɞ0-c8觩?⛠iA4] (w LQdSJ~Xe7I\^|5oQӑt|T(;$1S^ђҢ<^ڙ5kX/8)zVe5r3(Bɬ<ч$5UBQqrX5Ijk`3tHY4~B؇!@\B& H)ifnI ;ІO͗3@⮩* WLOv#f"𜪰Pp3!vs@ګu>/zA\/JSXI=C_:#w!kBil}τn]bovBݶ|NxPCMmчE(cZoһ{KV5f5x$kP<: :;_F]dt  f}7l173rξ7o PLiZ&ڔ8&c#Թ#4[Mc/ 4>`\9 ^eO,@B2VtC%MO d' a}'>^DXQ5Ժn?zdg F4q;U\9wEQiixks~鐛7i2Fj£?OA`qV M&f*$~u킉ߵmP+Ba!I3B2Y%NF$dT2)mSq >i=jj FqAL+)q12IҚjFEby<qOU WH'__5ݡ'"ȍyy-+U5r%.Jn4*| ʮŬpcy(XSc̏Ժ-qַ q R1W>NqҙPǝ+ !I58»D[56s$"F*Tl1(dNKtck_gVpZZTQ8R\'7bUDed&Hr[gAj3)w>'wY6!3>Wّv."~崪%5ZK_n^f^/I ᇯSN6jQ2$ 9*8+h&ޖW|ȎcL-;nn0oȹϻ~w)g=qV6@7ݥ4B>V@? ]coF‹u1ΊT0\:_)>y 6]cTń F3a U һXb y'ӓ V󾦅2A|gdҧjbe7h8]ndYY] R\=Od՟ ICvV% 'm^==ėJ&+S7f$gF JMQ10 %@hWb+48 |:+jުbMUFvRt |~&%G`Ld&*O/vnQ}6m%Ѽf }Jl+,R8=p dM97뗄j*!8~M܆=V1ږm~lx`jc8j{ro2C=a_Mb췋p}s3N%cQuYwRtv`\10֖mm37j&izIµ?r3Xb\fc%G3Qy%#5B£iZ2 =&۰rV* _%1r'꺉F8\߮ 5Od3-8WttC!=Na  jY)^T3UH(tzÿocd8bMRy~߀3;x=+M/wԡ^_ujHE0wJfF;Z m` Pw l#?TJ8p*GNd=c&z >W(\+2: ŧsR%=xj Uf9%Q)]\r#J" 2"7M%Mv c#F_lUjY0uDLÞ|Q6yY>cA)l|/S z*` !0ו T.Dd+}lSXW]gNt I? %/E ٚPgg]Mkh#ԩ\ QIpd<wj8KRu_+MV *Q|f޻s^9$O͐7TSY0K~CtoReQkA͕2;:f!Mv*sz=r'үuoB2H FFBƻ281<ifX I $g-2v% HL B=N`Sq.R>]*U޺.@]wxx[AӾ kRxǞ`CMXnԕp?@\[!"1,`[ÓJUQ'(/5EB2n-"JsJs ʵUɊSBf |"6#ɼTU?}/)͞65vnΆy+[6RzM#؂M1%IGso'GN( ;,]uID \lN> 9cFX?.׍MW8)Zpb2@`Bv<Ez&K ~0\滑pI?SpݧzymbZ2T@;)QXGMSy}w^DFw1tGն7Dv$&ƷCq=c?NΘ4#$$v/l 5iAe8刑fq $ {"f4Ji/gw(H罎]B\zBOEk[U 8xt\_4ڝ-TobUuE_l hYkD $&bA{cL?VxcxiڧcP.r v@Th_NF&J , }|;dhSxOxEzy4YL̳6~-sq^˘9;]Hb[ZOU 3Sӌ)kYvCVO'@/!qV`(!uK.9u9 $ɛ3]Vi+roǷW/f6A /6mZ ,`V zVMm\`F]ohrKݮի]zp<*ܺƺ޹["(xrUx)Ϝ+>Yy3n")sA6t)2!Lo``kmiö$wSҨ/ `Q [jT"1 6PHih^B!m GdԂi8S[{pKzeJlҜoL wݸPRI`K(i [G5 }If}Q"qÃKouO~dz絀 N}]|3|Y3%WCoG]Ԣ3p`_Ңۓ'C@KC6 ~űou%N!"i֓"pЈ8eM= =-I-X I㵍eID j*<~獠AERZ/Q:$& 5185 6=6M-902`9hcf=`Ck9rˎˊEvHV؊Ǎ{.P]{A5A2yfN&" tkSNٗӠ4VhYZE:՟MQ[+|3 H2p}%2WzNY8Tu"cMzTVsC(vd&>vqW0MjzzP&cʮsߎBEAAXmB% Wq~Su9' z5UkS5eXɣpw%dA==gjC ^ QוB  q>Mz4  %f+o_[RxɭHѲ<\L-ViV;ypxoO%{sj1^[c6J6IsWWZ GYD_*oFJL) i69(' t/H/,%HGoi낍]**8Ġx,9d'_s#;p@EC]D뚓v2X1Ǘ.;$d+xpH&Z:(DQ?A4UmD[3ȣ: .|5Cƣ;Te/RxK"y/c%a3~ob-;J6Veտ"*U7ɳxKh<35M\2NT[gċ[H .Z2Ik22G_& ?mRXzN.q? [Z57>2qH;_H0KhS#IMyun;>'6Z8ȄwȄP|;S^)R"% 1},B (1ӿJDt}rG A+6HnpEqMXܰBUDCW> %5H78 7}9d#.FewHG~báHn*&]5:|-esD?M>eotWE{˫Nm̽Ncі^`5Y$T lH?ѷPgf%E2,IL|t">7&(ܼV] ?؄O撖)1qGS%hMKk%(DH|>awG`hz,LX!M6& !I[LM ^UԦج 6?~yQGJ3leDW0&@g BCpG=^0RZ%m'+7 mCDSbF֤_yYCDK=|3ǠJ?>ArH6"MO xx,MwQG0hF"X YA?^pSp(2%IpWlC*gw19ecJ=O1<Ԇޠ? bZ!o*1f -{J[ŴE?ll؉el"2#~;v)<#' >o}t''C}a¦e$#5dڌ?Rŷs+ l>draQGײ쑐TH]厉o0*]I{> Wq+оݗ֒\/iv'sK _Vɟݵh6ު[/%iݵ"/*|]'M(={ >5Ltɯ ?BT; UdOQٳlEJIn)QyuIn=?$W (Aoe`-MJ"/Fb}տX:uY% Sۛ8Y?{<՝AA3\D#߱`T'L[^Ƿ $Ч8Wf9xh^n`J&`PltkTEop}^I~D.=;^vj3[%;)&!cea۞`++`T@Ge?|{rfl`  2|yKJ»aY[o]h #I77 vqpwuN8r {/2bnF4d 1BC)׃d~Tf#1 `*tpO5ۓTMMjJ: kdV\6EHe8פ}{X~!vxJtdͽZ\WoV?O*_^lȀc͹zpXuu+[з@?]6P%\Fd/{7>x? g2mȨ/Ù*42v~a%r+O |1겔$PVP5G7=ϡ&&H%{.e֍\x'xމVvX!12ULRńF)\^El#'HNj)ea&kޠ]YM|BGXbڕeNДF!cdfe{]v˞W$+yTu21o\+˴KeS1{Ϯ%ƭEaBX:I@)|Ҧ0y:r V:P[8,_=Eƶ%-7ADY0$(w=V9?Y qui_8umIެE?.@ aoчkyh{J˃q (Ioˈqx0{4Ȭ䲥.QS3h4?iW%#L5%0(uY\kW ςu>~f4/)"l߱(!վL` iR C/A{pa(o5z3UjOl*f"$'*Fb !?Ks6vTJ'$U=Z R ^dUI`[Dq!^r`hnǶju쟵8&o `4o,1dqVe & 8(E_g||ֱL'k6I=^pNp|5SQ#ܐ9s+& w{ vi=kc{(L3ꢜ=Y.#rD;s*b 'S@{R=P MgF\撙\z_k2.suEAPeDW G CtMDUD3^ܩwa}A|ˁ&X٧.9`8#w ۷$vQUkJhNO?W$4޸P9U [01/Ţe;BfM&QBnj9k.oHy_!^2JY^+pɝhO؀8mrP2f@4AB/LY\w-8YeA](ks'*9 Z8pLJ/ou)[ZP^ha꼹P\k~> fF&.x){@u( t~X s7$[7#}tx.׼xW!d׌3d~\VX>`AhyTfy:SsWC >JԜrlXO+%Zv&v5yJifl1ؒ`\p/3 c&S@sgmsʴ⾹2dM0&{1?nsMW{Tl!a6 +lrV׊ 07L1B$~F-;e.P'v埘e6BPe#9ag}Ù۶&LYV[ sT=ZUT6 e.3X%Ax21!㏓ddmЀ-.|al86e+dR<!/YŎI3nMMz[r mנ"۸:@>x FO#'826YiJ24:薮d"'|<8 d/ cD&4rg/9T;2+#)Hp'Q%wlO=S AW1rMN\݅`ظfe,0%2 wd/6}T&йG%fҕ>18X0@9V"s MJ^ݙ؋|Kdªsmb)g{EL0CݔYFJr:0^!N':QqabM|#m$NJ !8_(:U3a![󔨺m4z7WkQBTeeV]̀{{PC׵~`pYle|Ps32ᲃ2|NIZj]ygdp;+}XJbFTԞ$> Bˌ *>vp{h>kMcQ"0 !+ۓ"mۻ4DyTJO ^Fg'2© Cķ,0 %QP? TcBܯ3l8#] 2r萗i2ˮLϱTw9{B尹vi"'}+]A4!d}bɒ{&:y]Ҽ&,nȿu$MR"D:q A>/`Pv/a6؟̊Ng Y68PD*Ӯ쵛Έxb('>eanC#mAXs\%AU"Q 20TJ>Ip2a@OԍL]PbՏci`[=*D^m}RxZl Z(73[$Ǩ'xC$s1Za-@odgF !z+sJۯqD I‡Cc@]"z qDve_ 8u_FQƑEb8)}6|{&'(!È|$rI7JÈaQqg~۩-7&QkI|W1bEdafԷ# ƖV'ph,֞j:t3[ԓk6aQzW!GtFojnha˕rܩwFA)yՙOOؖZS[ Y 1!vvg 丝lAo IZVgC .;죗s.;s)Su<}"S>q 2*t`{<$ك$~EP1  TYpĜ7;Ȣ\/. 4]P:!wS GaXDw$d4u9kt=pK(^nzDu`8<9q܆EÒ cңrcҤE$WoJ=2iu\#x׳'f@ 4tLLKrgʕ覐nD62o~Pu5+]QM1R[Pu2推 ϲ12-$Y~WyR{%CtnGtڡ~uM*`-jM%C]lfQvn ٢{dQtӱZe8g+U;,sZZM27"Dpȣ]n: 'Lh-ԫ#ksޣ(%ÌP*qcv幭u3:q@H;y(R}OV%#EqJ V 0[\TP:9z\ˬ_-X9#G@OO*?@{uBgcz,ϧ{> N؍!h߶ȴY:pFd. z+_^' Sh&=O$5u5d fFӺR6Ď29zU$oYs5E zo$ {1hzDr;~< -bB`W=_X[;o?<:I\fyC\u.'3H3a)翵 @uu 2bzoޫ18o/]Fj޽Gk4+oIb1b3Q^zC x,^-)ߚ^LKIS,s ŭŕ]<3[=y@4kE8[۰WsoU.Ћ` >QtU=ÈYZ,D)j;XcGְr7 gtz?6-c&`kj; ۹Esi.OY^yg b%<=WR3;_sa~3[mR 6sm: KL젶F !PQks!(䊻"5hi& ^wTaAbZ,4GQ Uc;ngYD^.{K+9B:NHAd{A#O*&^3!tBZZYT D_ --);x-Gʄ! ;h'T}t.n/XfM+8t_#3[`*Ӻ SJZx> stream xڬS]%͝mfwVm۶m۶FUf%zO>{gEĚ1#fJ¦@ {;zf&= KN.4r3r41  Kwt4pPhRxt4Pp;\B__T.@  - TPHNF6%WcK H 0w034gX#5 dk` 0w2s{?Eo__0%{gg'K߬JbbaOng˿nHS{J/_3O.c o`Nlig N@s#'S_t?/98x'Kg,3ߜ&.s[23+vffM]tW$Ll<@3XF{)Tw*3 -_5_{66 F;wEcccdki_5v1a;010h,a4Ut1ٿv@'K;_mV=3YXX#]@;Z_şQSZGRR`w\<rۛ?0""ozf.= 7 ۏM1Yn&U?~y_`LMU#;ӿ? M\8k@ ƪ oUzVK=V贘`?3hCYZq}_z>w{]C,gʅDZ x? e_*)@!E'I ~Bƥf~;l/jRBtD_8nfK_/c#}xq0FX).NOM&on+m(I^xV]Ȟcј3Y ͿAVdoBbY&EdW/96xҭֹc-~6GJ~hP I /g&Ji0q!g(kkDq5 F OT&w QKjȹTa$$mJsM-V,uSrƪzqt`zKlJ9NԎm3Otc~[nOo8{ ’`lgӨT5H,@B/[qHs3nԙ~^vHjV_$a2/A MP u!#q)vUfـќ\V ۥk R,xO}f0 ?*( r#7 ң•`P,= 97xbcqZTP4 <75l){f4m_)iֈTc\X -m@hAGG:s0I Y QXw d$% Api¦/D{K"}~ͫ %&ACܖ-r2@@ $sGay: ԢK2z\ vCdZ~0K緻҃A;b3MKs4tLQczÉ+4f?b}H|j1ADKv$Ki)*+hfسT%հ3srmw~ŽK^f̀R;b0om_h§]bgeIJ05q=a3qU4Ww:xeEP Yxjߞ)Н$Al.*O0v_@6 1oM':U [' I.x>+&6YNqy/ٳE0-|wq c!f8RB5\?B웜~*=+߅X~slDʫ0LZRz/73͉oG-S^hJz:+|1뎰3MV yM)S$B%xEj~P@B<^5u E{ySW880_)dB5괾ȕK+ڠR`ވLO&<3}bfxxMbɁ>.RRgFiVbE㜁f(cڄ)ɬG wɮMmB ?y[Jęv[ 8ӧo G [PBNe[=h^"&ԡX/\FBo#Pə1 =zѸB5v|-#M4oā-z:4H!ZldS(Ph;j՜ᤥҹ;~U/|bņ#rPsK7=g!]r8ZƌbKQ!yW䑁[ ˞g:{;j G@f-}sIazJG4T:#˓ߛekÙ8#=bX*ԯ/ J1gK1,2FH]S^Lu]W.2DʝbSz}Ƃ%Rk[|Ѱ&5 rӷƧD\[M,};͸a,PtCPe}Ciۼ:o 4+`CU5r}݌$?t8d2bw.+% .w`:%VUga\iI Vt9}NmjtyЛsByk"?e/{g.2V-K';sqfY$:kq62CO%Dy8lB̕Ny6u)ZӭE*Z|5' bT+τ- Eztekڣ&̓eY\fZ** 0d3`1*'9geǰLV`zu=)Jm[`~*So⎌}mL6sAr? ' %fiyT=WFw6EQ$;.I&FBnN<&|VQG & I僰K?z]Yi'e]`H.^.Ώo,F*&ņ#wd?ڶ7_3/`jҒN*zZ]X`WLv-~@R^Kt ;oBȖ^T7¦d[M6!f :p$o 3 v)@a߈w_H:8(^y[vM>s,gwg$."7$ߜYߒE>7aYnp]K8c؄s]-.dΫN$x4'uG<[vĺ<[']fۜI&?Ul u ЈPUcX F)~v1]ENy(cV =Ӻ 9t4$=4_PguM 09NL;!6 |+6YY${Z驠كQ\țN.gjlCŞcGK[њϤVQj8(*\1ũ׎5kњRr_0%V$4]a tO?Zg_KV x:> !P=; z'f׎SZH}{:.DF%ME njycv("w]$rC3s C?,(B;#(=47Mcv*uɰlO(OQ8Mu\@22{ ]m?q1]woVJǹ扖BP&t|ckK7{6 ;^x_b 03&#i$, ͌TG>-__kV(w1yqf;5-޾xvejL'}fX]},#2Rh7oi٦u(n]un<_usr]+>:]3y=+zaUY)~EErJA,ڔTo k=;N\(g󖤤 >,0~8\G\EdžYQp$A ovUxH7!\T|e{{L Q{?Nkgs<<9q P=-%vXrIEuhS(ӊivJ';& :2I.wp8]uuҊ=9^C]xAINX+ŋ.3\* _}VX9+F%^$%t ЇY Zt~/fCCP ecfK7YPT_>߬" =3߶mu)ze?1kʗ8XUm\S`jd}+ȅ}vƥf1p;Co.F BFD}HiE?Vs" n_y\!l<$9~ ÃO&`Pp!*sL,"ii$;}y4Z/T^?ӷxu:KÃE;keiK(C, *V.1dh21xmH2բ:}lw(N3,5=g1f,1ovFFJƜ@gɃkڏkU<2||lZ. R0@*~R*GYGa9FlBζ+-F!3=g :tD_qb.&CXD{e97W?E G9 r=H7T=]68 pݻSM.+A}g ], iU$?^ˊ_ᩛRC>ckH̱krJLz!,8;s]1u[ .XPrR?RG<%s#|:\ҠVEjh0Fs Ү)4O l⅝m&Ԣ,Q꒼oN l uօ><Q v09(V$ռLtYGC(;᧖k̉86ku{mlkۺqAJwzR>1Y-E>o "`^/̆ "ѦbV\;"^gOe"q}iHءMYv)L p8B,9yi<*V#] %ݘ:iU(o8ՒaeR E9%_*G3'iK!eGy FĬbJ`ZMM(͇Gvyw6nz4/z^!@/ig_)y'",2Tk Aj,;ae!.Kxy:Gzq C+@ЦUʆ֩0ƲL+٘\Y{DĀI<5ƩA.~(;ڴ8-F%}3%RC8-EȹȕXmuJ"MTQ Ъ}l(+^ZulHa} felR=4B,m_}C V$4\Vi޺Njxqa Kx9z2RQ%D|ٜ|'rQ#kkA1ڏ !,p=挥]Qb=@uY3t@;**hsK c+)mQ-4&6b586lV˻&H|)z*4PcI; h ͆0`NP]3bbc$DEE6Glz{̀jBVQBA0%d7Ƭ#jK/niV zԼY /M!NЬ|]$YP}r T^ַ8R?rtI){VMЃ+`APao[ 8AѪF\E̸'Q{IG՗ :6xYVS+ 40A\{F 󆅣y%-vV:Ua٘䳆~*z$i{!EFwER]F٨pf-ޔҡ<<$F.JI;B$Ne*PIڍqGџ$2tdpiq ٳu3$'-X2)R+O7hKh@܅YmQC1cw5h@g_kfMI}42ese Cp@SP]?$)'zg%F6 %qWf~7/'D&)` u© 5# bo/r-Rg8&RꛨfCsn<~R%2*Yne|&C*_̈́YUmYcE;RI0uaY5V4 kN!Y(@p9%B 6nkWT'<3F4Siu؏ &,*4WOL^EFtͨK49@^Bf yK g10mi۲\ ʹ ͔ 6wԃ BDfP5CzDPbe*8thk~X&DB%$Iw 1ri w=x~jf}(L!a|X[3.*i,#뼨i5>MGk*T8_oegZ*v DFq pDX=JQ`U}ɡ]7Gqֵ$OdzϞ_h^\ >MIPd׭͢7|q<9I*yL/"gT_wH"!]a>o;\wZwH8~+AӠ\歭taG5A_,wZ5(sbw/փs~ۡ%̻Ġ)q 2Ė\&*9D$n1mp"+|9B\[$8,n EȜT巋ANq4ɫF,9tG-܋7rsWYGV7]dUc5؍kT2lr̍g&_72iLہGʧbn}O2d_7djg0timlܗ(nc˓З4r.1e핐OZ8|)iL_y 4[E|I;o9&@=~b~#$׳$%|L" 5*o@͗adT))Y]3^,4?1rH v܁r13jH*d^L|XdP &e-Œ;SJݳK7dZ!8uwa@ARzɽrڇNs v`]LJӞ8D୓e-C=AbG0cgɅ}1iJ4 {/eE0lce]ϗ3tV;C(Ï" ]$_ib)j% yK~`_9΂D/F\ATZ _x%xL#@N&gxg3o,C[?CC3߈!SHfg[BL?%Ō/V?Utlɚz9EA(lXx>Ʊue*֩/7=PI*[XPBe::{c0ܖhB7}`4~uo%jz"﶑Y&'ÂV82`|qJX[H4޴Ԋ8[YGKI.;QFW p:E]R&_!身>A|m糪uݎ(ȪѦ -i+~;;L l1Ʒ6Kb _O:Mb^BX/ik ޕ :S6qmYM\n۴dP|ǃ<6SnlҒ{:~V&AI|J6wkydЌc}6U9o9XZT>_6}1f0ni `sx ݳJP[fSu]HvGd7%WwU54/έF @?30 TsբNm"ܶQz'#sesLR'IAKsIXׂI_3yE<1$š)t[4LfP]_a{8}oV a^Pm5C,MN)1$"kX7$l6?(/-vubLͨfPpBٔrȡ5|Su QЄὗP;ebSOnpP-`?U9UD!Dn:7>ɠbx"%f-& {Nbٔ`y F{@jXKQMY1D`;9 oA^deZYEXGb-¬lR[PF3`k0g: jk[ݏwC([u} 4R9\y`[EN˷ "ֱU>=]ӊpuŋKSe A&{`Z'I3Z?&cjڼ1h3@^: S٭/ bW* d+ (}KHr24B QA5/+p4!㜼JrTf MFh7O.2a$j@NL*fdS00hd+ȃ7([@9vY)kHqE0tP7Vr\K^TO-dP>o wr΁6>IfF{eRO@= UYrT;4(겛 X`[Ys=B,Z*vXѣ F=f";/ʍ5 sl|n>ێ~=(,t|а?%Qc.֣{{eVLv 9{r}WC$&. Ft' 'h"4G<ĊY̶;Vn T1W[K<}<~a o1i$^>ی;$3ܑXhmzQWTpp{C~h{kFMםSnJuUyOLհz%CQqLٲ:[VƅGJFc bנڔ3+(l^ wvu*=N+Ȼ%x44!.\UlL[D;'64&)[] Y9)I@84rt8@J"e~FP+dHU~p@pkʖXqxBG! SbIWW- aQ^25DףÒ\#-v~xȒN&#!JadDULhotϘiY외ROԬH(sϾLY;JQ Ѕ5XTǘr/]Gη 5چBğ_L |E> >ثkaճ(J>\»KIK8lD@A.FJ44a~wL?ЉV41J .ƹ"ȱTڿP֥R~vxtbO2Nźy簯—BXMf;@Rć^8]{(3djEM"<;Is#*í$HYiGK9gM7z'; _KOxOGp"6| 7nSiM 1=g-Xg6I{Ү.$&I&?qZw߯T1:ښs!#ۏzd<c EjؓAEJ!|ek$Ga^iQ:_n姷q@3E?y"Bz:/ْ;)p["W\%*M`0fJOXXbY1yH`⻖ɇO?qlizS~ih50* Z+gQİ*`+>%пQw zGERlOڬ57oO10SÎ2|nQWSoKMk(>PǁP(xV@u;TN|]G&ED`m1n PtaRWuXiz 8s} 3;W Jd#đWkAo`_'5:8yh=v~uSUMX-,H^zQy=zezarIԽ wL5Vȉ3:nLU8[H߿k"h37)``Hy5sLfei?25 #}%B 3ˑcgoArtHv޻7J΍o{!ן9[π $Ģή֢( hHjwnTnr? )?#Npp%Wxa$Kez%mr?/ѩ0!KΤ=enVӌW6 \N5kwm/A~׫[᱉.E:NkPyqt=nd6ʎN,q2o s cz%5w ^9Mc2`zN<uՆ둗AQܠP{ViCO:*.2rkwSr}@z|$XFLEl(^}RE2MHї/&foĪ5E)j[o\ErskBQYڌ;aW|1%ha[9K/xǚ Ӄ晟5?TMq+ˍrA<Hҷ]/h e lYGmlƁ|xgm *\?5z7gZH~i{`cOGvCj71y"96L&̎}_60Z:hoU/oq7w狣 ԶsS.tjz=ZTq:8YgLR_Xl\ʘYh\),M #ݽrcjҙ_ $qj `i#]0SZkƕG~1wd}\7(*9ή\:]E׋4%j;94!eXXENV{ts;qI-h|8_@c__ *ֈ=EwQj+(\)ܖ bDs~)"Sgr7d6JY)@<Ⱦ-z,jQ:sy}͔"|L騞(||S!E du3 q~D"A%maLfMvbT-xf*p/esӋG# *o#㈊˥8O:NtdY#gK.N"%3}Քm.)gI*[r\3|ϡ%^=4F\$RBˆBzMEەܞ*,C# iUkZ2`M "`*-Z"N n~f%oCbRfAiK7gJ:h& r ;ik[7kmi h8>z8\xJdbg^!T`L4 C'6шvЙ'n1^Ew{P@ॐ`+\ 9UqS,q]ʖ l0nȆy!}^W\.LL ъ&_Et5JbfW39kekM.mVE QmjDژG>=+o~mVx Fߗ&>ɩ @#vDCؗL3C b,0Z t1ZEe)Ȧ&G,٧vBU$- rY7EN` X/|GGX"ysGNhLFφX4J2ӷ>>YE3 Ws4*xfM_~g ; ŁF}=/m7pC7sɬWش/C{ &sRDLdfΨBReT8P7=n|Ӭ|!]"yяn'R%h{9WBw.C)g~qrK#e>ȠM$`IIUH±T,SaqTc7:;ޜ"(궪$Yg:| $ݮXSU؛< V Io_MF%רU[DUCW17&AgR> ~M JRV {l]X@xˁyYc6z!d=>􀹺ܲc %}Jz0~[F4dqNql` n}wrVxXԹu|d=`uE[5 uV0Q\OfE^Ny`Neٯxtpi;W(jUӐ)̑M^4qA.Pylu8R-W>,[? U\;H qfpFx8cb("j ZȰhd,YۅrT{V\g^B:*%'»M$ n+{uX@-cRyCUI=c, HȀ\&|Tx${$ WwE:4}^&l?F9_4`u\#[dF}n4#ԋd&K^r]3_Я,p.?¹F1aIõѫ,l"k45ʴcRE+kG|n3/-8N!#o)9EӖ%3I<+&שΣuF_e. TߤIg/H|x,6P;TWs=uiAJgNa*~v0,Gy[4bфtQnFv4: rtJĹ1lgg8yrYWVJHBvJk'/dm;rs˚6G&4rIJ\ .&gP /AeH,uoXnnH6rA34JcWxpݍxqvYk6\nMZ}Om]ZqU-7ŶH׌k'uCA.5oz$o[ 3&f+)r*jdž\Vy`/V Fn(Lэeo4=_Q!L ;]^&m#¤ֆ<=B Q=\ѣul -ɻp(5p97l*\R >$WLfHhK =+iL-8x\}(:Ȳ( YlowRi"Z1 Ңڕڜz6`eDO~ahxEi.{:G1}KOqc`4?qbݓW#qI{xkzi<6@}7U~AcP^mmW/NKEZc R#ؑ: 6e$ԨLNp*&~_BMfה(LA!7Wߦ$v=p=b?bzD5]u޹0?HQ,A*>72 7haOpv%jmy n.^) tc2)㴔fe+/mg,Ѫ:5_-4¸ʱW&YJ7}tԼfXVUTACUX`B?D*Q&ZV_Jo#udC~xfAɌ4ϊrGF7/E& T_V|QW"ƙ3Ⱆ@xތUwJ ipjV}D=n2~|\d7SENIAOW;<H~ɵ~;eUƇe^DFn݀4V#hRwS_$E4d  Id^Eo>h3u6YA<qk'x?5v㬠Hvb톤ZeP*WZsxjX†=( LTBüXF;"|ӊ& _P aEɰXT:1y, -Nr<5JmdABV v@рBϥk,YT7zDcW3 lY!FL|:X%X("Hx=0A7{7 ' >G6wkLXoz;Y#uڝyQ) R{ʗO;E »o﹣g7eqdE NCK6s raUR?o z1"1\,{':È?mAKD"u)ƶD` K_g- }3o{y0jz냢t<-ݥҍQ78Ĕz-!q c(Ω -3x.7w yV߂X=ے+Z@zՌ{ Oͣ0~eT8a-9x^{JʋKr$UքʹA֦dkRS9oDkzEP:usW,2s ~!9bD(׼qz+0n ~̇ShqFvFxcښ 'y9{o#М&d~U ]O8a<|x\uv(SV܃\xfAPlQ\ γ=W{P.Hy}Ampy>T+ ٔHȄ:u _?14]ʖ_CG/1) q)^fUw#2~ywߵc{Mf XJ\ȷ4з]}I{KSr:*e9EC4:Υox.ξ'LJ@`l1RxZGZ&Ѓü5?Yi6`r:C@6F &N?V(eѯ$º3R6kNӿgb 8 -y•f2Nl,k3 Lcf Nga"e hҙ^ֲaҮ"`Pzʓd(nIpgh+Q0˭r h̪AM"|)s\8/}x!4V/1VYKv`H%ӛC2#?Ý$0n=-yJuX_tbC'^'B1<»28>>_pz$<wEre}Zh{TӱlstpcBw79 =g@Z; ˭:dPāΩ%6hh`?(n}@PudߡfL_;i@gUѨ4!`L3Fq3vtu_3.:?d'*qq;V#q1Fl 빼#ͳD=S)=VخS-T2*Pݳ>~!YuyQE7 @jdr2U]P F#b@aF[d%@+UBgڭTP1w/hHqq!]_y Ta%p ~1m饥>~m<VYcErKõMjZPf"tM|Xm\$tp]XFgVc] kaUp=H{{Π endstream endobj 4379 0 obj << /Length1 1644 /Length2 14716 /Length3 0 /Length 15576 /Filter /FlateDecode >> stream xڭc|_%vضmtlt;mc۶muIv9;Ηv]j*  #3/@hkboh#Ϡbf k瀣s23rۉ4Lf&VV @ haVWѤO?Wƞ Pq3w5sKjfp4mbߔeR)3;3'#  41s6;l}ۙ)͙/3`ffabDp0s:;NFv.{bڙظ_rp{/L UI\yX؛ijoOIE]v3bL6Fc%sp+ Wgf@p20r21svKgz#ytq61gcaol ?"cgn`abnfNj?3C7 #S{;O9ߐ;DoEy/=WjIWE#ۿd @Ϣ1r|l6'z[d\E4 <<Β@3S%%oeW35sڙ_003LhbmLk%W LZJ"%ˠjw Y8w,\<_P֤V\PkS.ysPhˆ/첀fu(ɠ 1fՒ/Nfiew(.6''2 G$?xnf?ɿ'FGn ra)~x~wo2|ur^nӬEMVw[q%&Egɸ`#=`^1s c-N'S5h^ƹq(țn?n^J'+Dՠ^ K4`FPֈboDL.5r%QKj0*ge9vwgֶ R'Ϗ݌%Z9cU0 -׃Z.wy@*mL#GqsàO7]#qQ`\gӨtH`b?HKu#ѿv;ES8SWXnBaQHq#hL6Z.h]( [x=-h70 *hJ X7L?K2ܠ7S,Mj 5S!@f{[d+<<Ԭw峕)4c|jLɪFKsk8lQl C=5P<0X D@SS--5ӫmzⳙŧ Sj p%,O#8R2?nFZ,2)R]Jʇ /'DZYj_پ3U5,\|[¯RZg@i0Y6|3&"q֢98l֍st EyW sPc)u'mOX.~XbT-\S4A^k/_Dَ+OQqDy~Yxn&IΏWLiZCXVK 'ߔcm?y H$x줞p )~:m52kzhMd2\{(,IJtJj9]+u2Yg֠LzjltQނ',e9Ed26H!\ H–V ~!ԹdL_4cCxOmvzTXjZg8!fScF'D֔]PzFy[ʁ!Hw:ʆFAB 5> wW;fyMTzн}p< ß1$ FM(pHj7΄ lt!V޴8 3 ~A b[9M“ޣz'=O!j$Rx*v|bқR١;ҕNj],H[5]u\y@D qƲER3}l"fnqp =_ 1LTW;tV{a@o͟;ߦS;fjOoɤWUI*쒚zB՝!]"<~+Q Wu oC޺w$ ssD )lr"ňκ)%aIL6 >XU,@d3$0NGn `R7rZ8; Kz-a/ng">\_xC`qgs&yMTh,P̚/Q,י`6ӫkl>aǜ歲>O 4 1ٔЕί oKdŏB3u 0nE"  Zoj}#MZ(  $}HFl8HaKT1=2O6fS/WG@s`N763%5(jGVaox:^o~ Pc4) /,Lo@jXdT [b/c r?xu ]_#x6qx#f>Q\}cQ 7uBHLw۷bnIC2r22Kc4%5bWJcRk қG64~%xs-+GfAY&~ ޮ7dQͷL9u}zV>D&QMъYH5GGWv->j3|1:T"ɷI|h6o*udYBB,leo]Nab?ƪ*ۇRMV"\U/ !$ М‘X#rؚ{=z. TY(kW4G81.< ɠ |:wK!IP\xjuxMt4TqkE+'gKzx$ɺ;n]%)]i"| A֝+_I9o[:"32Vz6=^f E-4 OsvTZNl{atNB1u‹C;v]V).pj *H(bۤZ|.“;n})͏$$xkT)L*kgI*7@u 4U$>hw;܏nԱV$c'b^MRQI Ҥ3*8"yoxZ67Z=y#mP;_Ghj:™f\APJm{<;CZmO&uRo$1 &G Nec:~<Sҟ8oK?#\L+.֞)!T6[,lgN~, 8m%C9JI,|KOJwf?e~EGNl~3n?5asղƴmHq=h+kOZD_6(J~k-k%7V=,a&ۈ[Asu<0ԟ ;!k+h.ēɍV`:GE1>daS+YhT{L: J5s۞5bV:.ނ:n' qac\Z)\0"g@0]"Ǻt("OւVx㫘z'?D_ޫcl~:AԞ|reo?=/MHYړd~,HמmcKN06cX(Oz#og U兤G/ 3߂iՠ<-8~%)xL7nYx1ܵYKZm]m1rbjKLE] Vc7vu)T@8DZھ2Ӥ;!"qA>+|2K>(=Id)8,jh> h`@f1N·N| p*tl̗ 5#iItҶ( z2v3g%vP:%r*L/nJt]llW:]i5[yo$sDZPk~uw}aTu:l" ;TC<9 a֜%#)?뤽,?plVUwфXd[SdmWZ{1w,v]6S F$rcΧ6FZ&0U 3u646՝M._!p躰Dg0DL>.(` b(EPOi<)㧖s+S"5G. X2c:4 e٦H~Beyߣ&fJ4R9yKE2}o@4T4e̟ќ mR`,`)c*=fm+\tI#f@h\PDwF)=/!*g^ZTeG1SX!iԬ*b)04^<;$1;S"@nG^iZX#ѵЉUYͅ2\?ut3TA,͘ڿ 0I12o"XnJcϫv< 3վt߷t JcQORDYuLkwDܰi0)31`O% 'WI p2Us^}kÁZ&Rϥ*~~`b<Pb)xдZ"WuKO(2cq!u+Wkeo_Bwܨ(&!{R02mH9~qzX3^MlDT#="Ol}78e7ޡɎF&΅I/;=)4s~#Pv:_vX*Ƀ4YdEҀ[Wveq 2H!i7. q4  zD2Htσ(D AҦhcG(*mˆ.ga\dzKyyݜrp ד&\e`//^^4 OLiГn ;ZokPZEU]n(xZҺٰ u+H+ɮI`׼֣] 'ⶦA4[!ulH `-\$JsvyqRrTU#lYΫ̡1]:U(f~C_tY܈M0Vs'ju{D*1Oz5jli4n5d`>+RQMX^{2O9R|McƘ>6^O“:=g8^C5`r_$ /:ǎR/؋@= P fdtaTlLa]) ߢSِmnO,6): MHDA}~<\S8X>|V̅:|<3X\@]pw?;Y_\SH)Ms r*yJ*8P?nI^}?2#D"fsJ’"Z6"i+yf Isy+7d4!We^/DV2J}Uv`D·ͥs@N-\\nYETX!UwtX'v?{n,/h]NW^Ħ]Cb44lԘjrdaAq4kJ򾊉/M@ȆIƊو>:J9j`{K]0l$ %AkѴBX=hОhGήg!jI\lX೺v񬆂LՍwp/A/_ܢc'<q=%7TKFL~#r{@GN(BT1@#-vuIrCNERY(û ZU.vv8J"g^Ҷ/K ѓtd(R:ƌmᶭs+[BoL`4OAmac»EAI)M>c6K7y- J侺BkO:ݓsT`ScY9K0b5|:$\G^'WO&]&ܽU4{0d@ )yqI\E3d 58Q} 6xʠH/N8lWnU łq]QfIa/\#{^B^!~h֢333\jgϘT˃8y]rۂC@-651Xء0Y9;玖 |QW7ӯ՝; "E ! .V"Yqeb m\OKJ"FY/|mXRl|6mH3=hiSF|4f8pNʗin<Bi(0Qn ?U=ͺsP3bgfR`N\KM:eJǬ`AVmEeHsZ,mM s~OU"%@3l8M e<2 Fv_S`.$=q}t3V,"Td7u1HƾSQ?JzD鎌y.֝>SCW܃˺k1]nwwFYuXH>^,Y$'i"E1X9UԙCz]/l=_2NA!*R)8olvv-p4z"ج62x,aa5 )W'Gj7. ыƆ.?͌^ӄ!#RlV[Ԍ0s,R:b}#acOĂcip@|?* c5}+%G 2O̓R*^7 MݴNEi{b9DT=V!O%#ԣ7y?C3ë" tBI3ܒl s?Dh+\[U' PjKYO&z5lj;LMdi 걺|VG趪@qa>ZV6~ÖKyp,^RpYh&GQ3J#nVr}հz(T(?@<н HE{F[ $ *rJ,胬%y}t]%5Z^] =4j{>*?H iZ)`llq#dPNi_Ml-eލuRr)D3(>`E|'(EҶڵgrOpS؛opjΣ?)dЄ%x^Wbn7E\PlT}Psof/[R C=#V@{F3-$r)J@|jP$3HWŸMԨ,7ID`FY 5wZGϦMAKt` X&ɲ:Կ/c0& )5dZ|z#6 [êE.[ϻ )t(iSKRBqi|j"YX8r $0]#mb,T@N:8oZ$َ6S4p jCLݖc8l^`*53v})VM_B4a# oʻ١#;?֫F9[2dk#ުG}\Mz`Ysʏq>ؾpCoR#q?Ƞ˱G`#Zo:x-0Y;Jnjн[pCYw{yAl4Y|dtGi^2殁F=q˚x Ώ{N3H{CNq_TT_ZPv(s xb+ xNX]VBj/b1쿩DDlTSQy\ .,̶IG,ivU_`h7 2^a7=l!:к&֎2, JP)8莵'**ݚ9Xyy"fX<n\g;%TcY^mA5Io"|-0#7)&/VWnܗBgAz-~׀}2  /}a}hK&A>DidɁNVb%A)躣ąvn:^LJ_y k13gkLlj*4.F\@n0z ~}" do!VCA<9^bdGb6Ζ|:2{F}@28}ib41|һuGvB%Ȟ) jN,[mt SATDUf  +FnL.|*1* ,q%$xR;Iv@O# rژ#D .*&C!D#)j3VxU#=k{GJP+,AbC\1w9 \b]ߞP)XxN4XApy#Qgd-vv1|fϪ.m(G8#!4l cEua&yZQ*?o>\J#omS%M![d琈"kg̑T.qg~0QQgPS3a+0SzyWtȈ=*׸;~64B}Jg8[fII6Ehň Q!Op߳o9ؑcJY1?u%6~5$y` <0\O\MQ-uh(t ۱*N::fO5πw#SԶ2GZDXpV8k[6sn!B]➜,BWM:9>DW{E|CkB)C R(@*(DOL$GCnڃ^by {>q-~&249?9p/VrgduC^viEa$>DӜ62Mfs؋/L79 i*Φ,wKSY0mwX\U9+ E+⻮)$1f3Li^կ !sQjI.u9ZnP?.\T:p{=nsr+nʳ e[e)`j֍0FAM2!:8BSBgD<:\:jREjqRZvTrnIΦM Nʷq6Yj]4  cW,7[::(rcnlI I3C$ȳ&ΩH@v5(!!G*b;qoDY:hh`&Y O* _Ҷ44~m`-HwW gBca͘s|hz1-3U^x﯈ ?Ų?ǿ*\HqE0@M> stream xڭep\Ͳ%*&3333E-fm13Y 3˒,ff̝;qߛ?3GwU2VVhj "f&@I{ #3/@ENсGAh*28((Ĝ +{qc4M %@ECGGL<beaupڃR_;%`ne ))(J5R@{"]MlLV@{ `\r.@Sn@S?=lg`p6=vd. Sg+GoTeq 4/ p0] X&@f@pZ;]\tNV翼`rښ3"i ~7w0n_DOM`4G`Rt SO[oMv_tU43w g?jlgerrW!D-*oL dj 07{xk؛mEubf/?jpڛ Դe_vH*QQ7 'e{yX}? g+3#33 |se_h$M#5_`SWg翊k?@au/:-#T3 džfDrLp,Zf$xR\\auVo%7ٍ1k8(S 3r\/nrs( ,{s&"1V5YnJ+&xu-Q;s'_.Xƈs"*hRр08'_NhFgg4Emtp3[} A{9vI]>YF4_Ko s' IKDvuiEJg*o U 1n"6?aXرbӑd]xzI݈`_u/2$aQ;>X4zʛvd"ϳ>kjBaY;M֯9*$n߮Vǃ _<'11W3 ܪOY ꮒ"pWf]K35$jh\9O8΃C2lV~gExKr EEUlwBxfc5@ivD̑T{-oyhEw ZfҨ fyW+u秇@#?.ϲwZK\)# ̡kkRCG$KGL!띸 bz ƃWGtZprP-/( \Y #^:_K y[r:Χ˅*4y^{z : ع)Y!e]lS CV{%vS05"uP `N)1-"ҞÓJyJ jJpx[A~; 6d] 7yv܁>߉]rsnuM-6tRY ;XɌ禆G&HD1AM5(e"\'Ӹ[{p1Óhu~Sqý}c鱎< 6R[i' . e.m@*2^פ"NU.8~@\m Uo,*gbFQ WjOAC ݻZ ThA]uU;S.fdQ Q ^#w0ո[ lk鐰gV+$\y ޞyjW c(F)0+Z~\VhfOxr ߑNw^V#Sxk SQȦ/Eػ'_i'4ctzBa +ҡ߃c v%fkKz6@W+30l e=ʹ"E{\~/Ɉ3HF*fȳ^E8|^y\oҹ J8Qw5(DҸkEc!OIQfxTBKhƆ7vJ}gOxR/j@?f-nͱ'TΖf)Ԛa!66qRo7u%t#QKGKP5Y[Uexϫ̋$7h1QyX{Xګy$f!e><C5!W )袦 e}Z>oFYa[U ~Tq~R ͪ%;֗6ɍQb(ήF@B>Βq_^Y &qt<$`PYUz_ӡ>ަ=Ϭ/Q«̱n­rDMv%x7\oh[o68#w(ISEWhOTRNN.V9WZj ~77rX@%m`,EzGXnE !%[ &qY$,[S p2IGt] ӦDn;)"hw$-TB9٩TwdEk}4g AY Ojb[ՋPfpLd'֒R%#޼":v@]#regӈ8ɹ5Jl=E J:9HM>,M%,7')Hf&dnN!ʼnT_^E*\N?CQ5.TH~/ǃZ# &ǖ&y[F2WY2+K%NճQ˔Šp矁Gm%JEߦ~@4j Roj~̭ߧ35rZ9G;f"J1/ϩnTԺpSiԍ}MXx 1[[v]T()lbӫK/([vb} }?P/9Ꝙ"pIdVEi}d,,= Eo8p8}/;0NPG|,g`CN, ch']01ˠKdvD{D/ij]G';zWX0Bz~lZ<~XPcEl jSI5Nb&TQ/'HaTԬh2Cs%v]n$[1[FέL!w3unM3J{k%q?ݠr=??|`∎F=5P,Qh`^_[7u:< a>Tڂj0`1 Ye\źO%Fa,xv3grB|Dٔ&mO2Oavoq\7 lQՏ|--fa&xJmƠټiVw  aHS]tݔP7Q0.mdɮTT0zUqX[ @q>1?A7  xTRrk)s p)(N)$ո ϤN'ɥ1i@!TE&[bހ\gGo4NL4mL329g;VIC}J % \ZTk iՊkVÎ]+~X|9_|8Wlaeo RB^p.:QZeVuG^x%*! |tOxT wTUFF' b1Vd|$ ԊSp,z&Ai0:H5<;.p$C1УNGf[-7C"Sq-leNBj!eڊA*nv[ #]XFbФSJX[>U7vV-CJ.?mԻ IL2 L5s1 ȧ&EqGw:'L?5p%/h2y_iUh* myWR>JhQ2Ş{4dJ9l% K*ӨKAx:6ﯻN&r(B>۱*k7.(gIv[_:q20!(#bNz }WhB])8?D}6H[Q㗫1h™N#ҖÕ) iStfZ{ R{xx $?~>MnC5☣~u[?∫[TlDd_]9l)|R8 Dd#.Xo92uuGQɿp3 nEn"xa& eáT[ h ix,rݷc@c|7.̡#崠AAT+F=2ݿ wKxeU/c5p#,ü ;fV%9>79ś>CV=T*3dL%lCc=::*Y(rJarA٢ge$drO^BVTr_TUPEc~1nf|m>v`EҺ@#in]onPэ4Y޻qC[Ő>ۇ' 22@[htWQnOVN kaH [gb?8 |}bzwګdb-S>>=bY\R".)Hon{H~bW#Z:N9}}J,;#\GЇI7G(e5=V7`a: ݈}~N%#Ƕ[TbS[K'{@sH'9BW 0x7X{ǃ}M)^@ӚtROB{dP 0ى% gw)]O58M MwwS wTB4f(rчVLH^.?%qsl$΅&ƽ}\и 87U+MO mӂ2xXA?glk"qbH6y8Wn)OE!s~ {}^+!3*SQ73i6A;H5yMW˽7;^jML8.BIY0F/D);f})oB;\)_Cѥ=|LZxs)*"I2:Do5ª ϜXX&նĞO'FZgG^R@e0˥='#^%޺<)W ^wM {m8*e9*8<=9!Ԡ 4 X#!Eeo $E?~#i8M!wyB%ޮ E= ,UN؀XX-7 .6,*bZ~*PU i=Q\S0ˋiK-MZ2L?Iq@8jRz:hv]+ݛ$vyDCβf{E^WAu8F n wR*c_+_4(aDn 'T'R&C+Ӯ6~<sKUDV9;C`,ua1ɠYcpúPi!:WM VB!ZK&S׶ T]z՗~/Z_ QBWY J8'A3Y~ǕK=qD-{bLos#s՝-SąE*Bz[䣽h#R9m" E8zJ~ KMۯi6p( K] 6F_G<lf,aRfu. |'T)&#x|s&cQOكj(kEܦCN!$2(Du0\N%8!3s;24ӌX?, /Yx怙S&(Bl#ZEP:,1E?_c}@Flw!hRe*'1-(`67,)oB-qu-l5=6MiLL5hVH2\eE|2≽蟳s\B„S͍yizcc!ؠ,v 1;>>7}YKM5Y'lK䭆XH~>&)w {VR\L6:Ɩ~ɣb.)Of"iٓֈ Ea[P\RV> YqHE^DQ)+}^uǐy-^!\eJܨ&jӚS . l֟2pgicb2+5mLKvNEoHpL-Q" !qY5u6moG}y,22lS*Yc M 88n3,U۹@Չ3z5SDàEBp>$Rvr~ M 1?cnu2=uK{ %kPڳ$a.qHq{Jd,&3E^ Ov%9~3.\Kam x),qة~b/PMiB.GG3Pɑh4 m$ӗ,zގA~ԫɶ.ㅾ'b-6xaN\󤠑2E`;F8x"ɞ5gc|՜r<ڇ T 8AVLI0+'@XAn'Պ"ay >mt3{uTYV4.2eY=| C:vg8 0N2u3J0;4ɊE2\Fjh ͔OߧL%NYGVfa.Ӧr=* &Lam,:l- ,Zf=mNJEV W>Z,Y0w⵭jB|2 Nx&2%p-|ߜ%K%0#:0؜k]cT/źFf+'L#kaMiLbz1VQ+ zJ􈴷[t|b'C`lX'>QEO{NaOˀ0^k(_[1xXi,֧߶Sͦ3 6ߒ}l+霒z6ܩ]8:_RxV+L;(mڨʛt] 1xːmim*,IGzUjwSě[t@QϷw~k.fB݀dqT[idksh79%CjwXN=}OB Kou)VۋRlΎ{gx]M0ӭJ׊RȲ{;9:2zJ{^LX=Fi \Jݿ58G7v~JOrQ2d F7}n3 / 5t[y #_msTX2S ]^I ́R̝Z:i6J@J+;9#B6*wN"UCx߼J`'B6f,vkm:uPLGnVŒ=N%R,+xVMB. }rܹćRm^(,W;˰F ) wuw8G$[[GӺ5B, ^d}cF"絁,c}o+f+ӡ?1J-(ͲW}{ҏg,u46,EW~W ̥PG#*C~LgrxxK,K 6Kr'PйnA9&E|=S36|TD/zNk<9='r{@Tx{:AN-s:LuTطqq= .,yF&qSR-XiF:J'35\K֮a? }Ь(R'8KV ڝOdo߷x:p$T-}>4T߃1m9pqWիumKaIъ5Fxukny}N"( ;G]*q,g5\h gN43h'VPKx_(ؒA4*lMdζA$JDlFX37x{%t]@#8ɕ$F"#Ȳ;poj f1Anxz]$_B9hq7"@et+1= 5ԃ\QqrPYVna-.D#5ZK^$/XAIr5,D=[BQʇF\fw\;ij|S7FOeV+\\rǪWkލNBL,Sj&tN2eɣ}E)(VfQ aZlfPO=kNs`<;X S&΅s؃ Wk"[;Zhk bHh"[Qnp$k]j o[GЖ y-{x_B[b Na)--(>aTN嫭uЃ%86?`%|DK90 G[L.#)*<ؾ#F˚*/[acdw~Μ0W%LBeQ}SJ6'jmex}9#!r֑ (5Zw,kp:(C;C)rlS*"y~kwSyIRvgˋ&JCC/kQ[A^%:FٽƖ?HU| Ǵr^,Wm[K[I&uQujsW$( >)q9!$x$񽾂SRv,C%UmAD']a/M=..m[+Q&O wx0KAv9{Ĕ6X`Xd虆 \}@t&rsz^کB/o&Ty&` 5X 8! sȪUEUg6ꍃ;Fd!|6_I!R&\F꼅|!aj9MD#{j}R[A8Lo>{lƥ?er9Wĩ8i!(Hx `޿r[Ra. qORh٭[e u5ر%MS5*Q/gĒ` "LU̾ƫ_[ $q-fX{S(n 9?4 L^ `1UG4{} E/IT?lZ\ 8VD6ȦayQ^19{b))ݹȹuX R"]215cQH7A Ⱂ0ŭa95wQ1 7;޲ ?'U|v:wFܮ^aڬ'Ja?ҼKb~`xd=Ԟ[y8oʷ/,,J `"g9"5 Aꓖ |h;׍`&!W]̀F#xCk=E]@OU)5rw<{i-oI; P4 k4.`S<fZ^o8!6S挰5Gi.|N:De}pZh"M: Y1q M|G\A5;*CHw CŒE?[C-fص r,]ɰw4EkGyX$PJ*'.f.^:b'K?v:Vt\<2Y`S˙υ.) .ad[M4LJWraH:-ΰ٥s+i3WЦDůFZ I޸jt?Onrhӹ/'P?7Ţ|XN9?/ ς|X6yeKuE:W}?-{F=نBH;bSzdG?i[Ӵ 14QF6K]!HgSVQmm4̠Ix4}SMfFE![tOtx%2@( eas7v1H)#xx37*\;N532ǷIv27oWn}9Z)?LN/9˚gҺS3w54Κ>tt_73\JÊ' el8Y<>/ڠI\XAĝsJh\lxOJu>X6΍Rt).4b?G eL[`4mQMeCLhQCKoTme(_3FCaBKܹmɅ*0IS2ZBX5 GmV:! 5j3Y/B+}B!^LͰirÀCtlzhv\ގU7L;~!_K|S ]ՠD:5S<:ı IÞZbj/qD[좶[†3(*5EXl-/śb< yr"w[LQl!A!au endstream endobj 4383 0 obj << /Length 696 /Filter /FlateDecode >> stream xmTMo0Wx$ ! 8l[jWHL7IPV=M̼ su;Uٛ=w]yil;<[[j<=?׾+v`&ߴț<^*;~&Q>MS >_P{=s@dkx;`VY`s4JaQܡn.Uu9\Y6><ٴ.Z.4>Dӗ}~r:-d0VWk,8yLһʮӮђ[*mLr?q 5F8@=@)& 8Rx uD\j2HV0CzL] bctI g$`htы0\F0s jd< I6zg W qȐ+#k .bsrbmXK7ǵH7Gnb>&jؐu1VljOu$՟qWS/%1{\xB!K(hHTЖ枃Jρϯv=k2UKς_:~$/ ~E+7ˢ/ l(/} -+ZXukoԝE?ZKq endstream endobj 4384 0 obj << /Length 695 /Filter /FlateDecode >> stream xmTMo0Wx$ ! 8l[jWHL7IPV=M̼ su;Uٛ=w]yil;<[[j<=?׾+v`&ߴț<^*;~&Q>MS>u;q~:fc_0F)lGιmu f8Gӫ6b"!YUe.`M{My?IC4}+̝l/Bj*{pϻƲO('$ *{>J-9_eQ"V$)MP:^9 ^` br @ {@(\,RH&ti m+3ԅ ,;F$БzFFieD(0A1a8yΠFpnù[w6p@ )9r9b_ia|F-(:(nQHY^`nA|n(戥K}s\}sԑoA&vqc⠦ YK^ʛ!_my_)=^ ^{TGRw1RDž'xJzImi9j'pͽܳ/-_Z,N_: ~iyY2q,nЪ5QN Y58.] endstream endobj 4385 0 obj << /Length 900 /Filter /FlateDecode >> stream xmUMo:W5?$R. d9M eCkmCp;;w~>|3E_?O]5߶w]Occ]=~?}Oyh9%?۹׬B|Ɯ>);vw%g43>\ 6 EJ78 1{~`W(-;]%=xe_,b+-O;q\L}UI--=BKE1p[! Mߊyu>.N5K)Wb٬8i[_uʕMzQ)V(Txޢjy!Z2P="Zd0\ÃGR\).2*Шa!U,H`+j.5Nα@VK-x%3%AYӀzΚ>kP#5m0Woþj.ZT$X/)n)#Wo(oRZ $Kp4Z-b\1ܰJ P"GXQi/8k^Zq:Zs9dB )sL-7xJ`aɽ)f$1 dъcCZC<73JgznHȰYɚTa,_-O87}KԴܗLloK+gJ.GZyVc48Wt]:P~`rZq.n1] S/Pu7Ue:?&?!d&1yHn5)yғBx#1ޞ]Go׏M?X endstream endobj 4386 0 obj << /Length 700 /Filter /FlateDecode >> stream xmTn0CƆ@LE"jD;oƤjgy_xN{qV'wC&]\]]u>t\qxں7ŦmN7isƬ'k~G]?ߓ` 4;RV_n86]{̭֚u[sfߴ L:?v>4|`0nhWu}QE KU=5Yw߇l?N6jwwv Z/բ,ko{&PaffIq XMJ0LfhrdĥP> stream xmTn0CƆ@LE"j.RC~8iZ)Ayo7?nkNy$냛G׎ծU[7|SlfM[kwʽ5g x=i6;RV׵_n85]֚̽u[OsE͡i P{ LՑ @4=tb/yVvL MnݞArjwf4P׏ީFT]Nrî}sBZ2pmmR?\rs<, X#.KIɌCH'hjmJIQ09da"2rG~\5hגQv]`n @v)(A'b}qHI($ux-JBJ!^I :ggM597F7FN}Y{}&Ff.pdk_ ΜN0VG9ʱwDK4X=CaCɁg2)4X(rb0/s4lƵǮb]ˌ[r> stream xmTn0CƆ@LE"h.RC~8iZ)Ayo7?^$ŝPIs77EW]}==硫nTشxGɛz?{k۝=` 4vN߷u8NM>(s&`ywS0jzQshz+&TuS~Hxqq`P<+ OC톦}SWUn}@`T;P3qtj}w*5UWSܰo\ze \[3. 9ff ؤdF@!i @F\ ` H sn4ȶ` $(Ng 2R0zd9#Cb.k(@.0[Czr aà8SuX$Q:\CAfpGR~m%^!N%$h&՚R #ƿp'XϾ>AI }3Nh25gNE'bkkؿs %|V !3?fc91ӊ9|u 6ZcWCab d1׮eF-9Ag깐3Z=I= 6-7p?)pegT> stream xmTn0CƆ@LE"j.RC~8M])A̼7W?^$PIsWWEW]}~{SCWmݨMi7mv9I+ڴg{ҏÄ~F )P ǦkZn;@1zz5= 7m=x Fgu P}?i]X<;k C톦}UYoO} A`TS7~wpjmS!詺]]ꂅK(ew&97\=̒5⒁yAa>:M1ȈK,x΍t,@F*&" C,zdWXPv-hakH/]d"btv"gg?|2JB^G5kdwt,uVT Jb9;kBX!00a0bw3W M";\88̿9Earʱs ށ?c>+q p~PrL  hi˜c>:q-+01~k2#Ϡ3\OLqRυ>¹M \)s9O \Y!O>\\/Au*[ӺkzT%C0t endstream endobj 4390 0 obj << /Length 700 /Filter /FlateDecode >> stream xmTn0CƆ@LE"j.RC~8M])A̼7W?^$PIsWWEW]}~{SCWmݨMi7mv9I+ڴg{ҏÄ~F )P ǦkZn;@1zz5= 7m=x Fgu P}?i]X<;k C톦}UYoO} A`TS7~wpjmS!詺]]ꂅK(ew&97\=̒5⒁yAa>:M1ȈK,x΍t,@F*&" C,zdWXPv-hakH/]d"btv"gg?|2JB^G5kdwt,uVT Jb9;kBX!00a0bw3W M";\88̿9Earʱs ށ?c>+q p~PrL  hi˜c>:q-+01~k2#Ϡ3\OLqRυ>¹M \)s9O \Y!O>\\/Au*[ӺkzT%C2t endstream endobj 4391 0 obj << /Length 814 /Filter /FlateDecode >> stream xuUn@Cx ,ei#$JW)R w8`x3f_,Y}..=pF=Lc겺oxķCvYQ_s9;~1_B4-辒O~:p̵:롫9Dsg~&1^`32(WB0(~z?v؎r8ӫh~?u~Wu]t<(V4dqy5jޫ kOGKWj4?L%/۳v _NU4(61ȘH`Zp0aASgAQ@Q LE)58ZP\RC%4k(4mA%MJ$*C6TQ.c3p4ct| 1v9y\;摴.y.i*OYIa%a2A{&cxs4c̲ lcw36av7fgΘ4aʒOg[2O[1[3K?mgS- }3 O3ev/Nz}\-!={3pII)dKdgI$[d$[HI$[$[$[d$[/¿l᳔l1l/%[K~Jɖj%[^JlIo$,v)%sRJxʚ>fT+cVS߰n$7G"=MS8鬧'k?G}&馿r endstream endobj 4392 0 obj << /Length 550 /Filter /FlateDecode >> stream xmSˎ0+$1$#8h@Bܰp`~ +8*=SJ]sCM&ESݮ`w z\ħmbo'ޚr028~}uHXz_z.XA_`1o"xR:bct\$7҈٘TmH@ ]W0ywznͩV+1r]oś}X 6g1ͭnm{!^ ' bނP48YhC`୤\UY=0ZĎiơ 7([4r;"A"e"qDgs"2dK$#В%#KDDNs5&]J[/G endstream endobj 4363 0 obj << /Type /ObjStm /N 100 /First 989 /Length 3516 /Filter /FlateDecode >> stream xZioG_1wh X)XPX"e_U}A6GBXst]^7g@Y J JpIr0Πdy%d%TR)AM%+$+sU ѐЬP 4Jx%T^5UJ; s2BCxFK8zєzPAe%**J cˑj-:+RaN0$:i'$[̎()-PB08JS%8cHj̧4Waʥ뽪h༒KT8SUyӲZ:L*FX>+€a! 7*&Dp7b\PPhM((a*Jx]ZˑV4 Z Д̽%--pCA M Wi/XTB()G@"@迧FhhQT_4QF8YF0[T/E.GnȥX" A\"K 'ȥ  \Z6(r \QE \(a*4R,]QΓDQjQFZTBU+3nF><8y6{?.&2pc5oҟ{ԡ҇Xi06Y/ >`5dh,t=_LsNBXWirBh'>vsK27@tw<'0.: U߅*4[%!:fv/:%Ҥ;I T2wҎ2]k|_*HWiNc:a$}w7c쒜7cQչY'[KQ'MwI8;?~~릮l^/&7b_ʻgON_|>[Χ ԗn/οVH`ȯHG򼞭*>b7U8 {j^U`C=fOS#{ƎO9{^W5{N)޲w=~cc6^O&:ʫFqU/&?xxzZZEiAz՜F9^8g|]̧Vzl܂-ٲl9/؊uVٚg|Q/Of׋?#O'.4*>˗ǂKHHFx֏q#AEt$XFJt6ⱇÓG_xl9V|h9ScEMC!r#6Hl>9;.pExM\a7t n]U?0+ 㟎~jr}^g/B/.-$8.˼VP;zmO6RD'?Nׯb#0\)\sn@n`L3bW>ѧ|oTPcOn;&uMo 7xO8jǓen5r|@aҺZ*Qެswp=[c(4]!Dד7]{Mׅ::g\\GTW6jg },:Sy VE 68L;}%iW]%f;6U7+!I>ے_ؔd73uvA55U}zٙuwBvdjfq\\N>}щzY.1J4=R&Z%MY =&/&E#!Cj(Tej82Kn4c̝2zygqqԝ3mS 7nr \C7F,{A@x-7ҶXeT+ð[*oVw73a'H~sqb/[!&p׏d\Q#b|DM.VWK7/_g8.Bر(jcT=t'(rJn::>G>ܣ۲-`5';A㜎,\|\9ߡ זf\elwyhkvw]wӦN[ߊ{NL{)޻ur/[mu6b[~^[_v^խq]^nf|Y/q=_}Njؠ}AV:NZ#tvwz|C̸;Ex:l)STdv\ʤ/=L l+NKaJ%QHR9 C a )KIH0|{Wv$yiN >eax*> stream xڍKo+W>"#Ë`_E4$CP355ŖX<ɏֆ0RX2e@_To,ܦ!W )OCIer:UJ1Ki34L`C`" 1F4D$f~vTsM+LO+ X\y(F)s",8}ĉ0]!4mR9HLfcl iol 21521/Md?oW,01 ?d6R}v#אĹle?:A*a lC!s9+QÐca2HL.rL/8W&sesLNe2yW,nɤdɽΊ%LRba2R02yӊ/QW a)+R9oVO@vVFvU&d[5bW5ruTkƞj˖*WCb?+Ⱥ&Ba] {#[8?nxvq"/)whh9$%bw{0e7׫Wnք7J{zuaY?Ώ-yL~|\w}cKqW_,a _CXm~XQauK~X<{IaerJSa+P-E@V @d}Y, )@$ [H>(|P>(@D@T`  @h -A@P `rǔ0QŠhe s% $cÊ 3`cy hMYD% %aXH$ K ×0aI"a0, C$ _P%aKJ°$ 0| CI!/a( Ò0D% %aXH$ K ×0aI"a0, C$ _P%aKJ°$ 0| CI!/a( Ò0D% %aXH$ K csa8̒0+W0@{e? *,XaI‚6Gay갽W蹰` v `?ϓ0|l5| *@TY>4 @PjP-E@Q @d}Y(, +@$ [H>d @ Y ,@  @X>D @hpT$wR~*J X7ZU+ͫkyW[WIr(7[ѭo[%[˵ZߴJgEed-NJb}*Z~vUr*jͪjyU[UIr(7SѩoS%S˥RߤJGEED-B}*Z}T)y{R_SYou?}I[|&E!գq?\٨m\gɜIYn~?߭}_b݇7+|y;_WznRx/vTv]?/Es;yw󰹼zz5iۻIO/tN+drxyxJ޷?wb˕}R1.|ܪ5yXd7~mN1%KN;-z-= xrh* Ϭt焜YO׼.o?|/w Rǘc?oƣ_~i3{ܲv^Ή)sOie̍ͶKaM3؃B 0ݧ͚6kyN|vvfDح%ɞov܂rIVi*vV3Sv 7 endstream endobj 4407 0 obj << /Type /ObjStm /N 100 /First 1054 /Length 5691 /Filter /FlateDecode >> stream x]ms6_1w*-Fl*Y;9g'))֕f(y+H/Khp$;WiӍ~Wc)rQ,,{0 Y*E{` #{ JĂI3`eݓZ0SS\/^p%++Q'qyt9[2k`n8].R=Y*B1m\/zyP%Y 4eԺQ nUy%B[ݓZhY:TC腮*穥PpfQ Ţ*YEU)'|a <†O:])FKd`Ea*[3}T9&}W]bQhUUt,v5b\WJڔM]ڄPYek%sY*Vl[:c=Q. 4†I;Lqp))m@V%%Vr`mme ,4s)Kmm2r6>ڴgmmUqжW6JmmFx5[ʵlU,x!biY)M֜U̠lrfͶ4"Q@>*FK &%ڬNͦ WpMq[ۂRu)-ʢG[[)lwIbk,ܣlVG[MpmmG[֮-TakӦ 3^zWݞy8Ū>ܟ?v?goXAazSk. hHpppwQ_^]i'<uy4eGVjzyكC$$=lWu6c%q:d,K|] T(%EL䶗`)F"+>bfTR%i7a Xc]q kڻ]j2^6w}lwۗ뷛]hs gaGpGnە5}.ڱi)S`ve?дG# ^>R5csϰ{iXýYkІ'RCMwpŮ b]l n+Pbi8< vwoYBCWw:Όe1&TCEVՓp C$H+; *GCS C&Vqo;0tfpf|[7ˇ5nϐCh!~ӻwyL$A؝24T&P"|Knۡ 3z22Tn4׸Nӹ nwe ˀp03¾W\ R2o{m ˼_:#f9䌠 Ѡoz2)B:9fG)=iu{ 2^;f}֯nj!Wx-G*S1 7"sNpT@5>$ QY+OE58](ۃz<1xJ(JLpR>xI96F .Dk2±J=L(gc. \fxH3Ae<-r"HgLpBrsXt%yc]P+I$B67jnI N5.2v h.\{Eboyce*('Q@p64!PT!.:\Tߗs4rR!( ` w⸼z5>@qJetLsB3w\Ev}l:J(rB 4[Ӳqg8b:qYdmQᔯ! NF*)qc{8<4wvY'o<;CcN;-}HOQǜ@'GII)OᙨΆk"( O9d Anown-boNFh ے@@S~OpL(RzFh^*CHםD6K >4z]5;,QCɡ v2Pi @9Y"&p֯ ^$L9k9!}zZļ=|kïrgE jr 7_޾cfdl<5sRn|xz')Qҡ{'}{ ip[Ź}[/f`@oR"&"y@(Z-g! +/!Xq Nr<!}AGYXfۃpCWq{wą8"yi X(ŌLw ܊ާbǫYrK_8߷hA>O$W' 'y(E.#pщPƹ{T%K+j1#`fȀ&-O7%錦t FHti o2H G[k$̛C 6EhH3/oUulZ{ ܦ4 GDn \aC~nn 8c1l،<["%}M)^U7&iE1i:1s܄-2BE j K,NnC5 }1.t(G:\;]RӅ]<P򥞑LÃ2'ۖ]6F)9CI{{1W7)#ƒU>eoG L⭴ƒ3y5rP%i2LQ҈A5 Bzp'cg& 6ߧ Fr?'1GZ8uюI "֗xCK\(C@9@^x&3Իxt _ddkdV>IjWᔚI[uބ@X `ٯ[7x3QM;H0e| h":Duq(iAfREL鍪î 뮭o e2Co s1Lh,/0oJJG0fUJsP!Vz&8y::" Dz붊~83U0k ?PדlA!@+re(̼0Xs?vЗ-W}PQ#^Ɵ0 zmFtݔߝEC8Lh4J6E~Hᄝ\Ћo3 "lU?8$j4VU'0kMgB=m!L _\q!'ܣ_*C?Vp!7#7;rg{yM}h^zu}8;Bu/:8@L3ïv5esp%W_GLsGD r|+<ɸsV `b􃆨5V nQ]h1-W%&' t)OFJ$^)G"rRC'tN6-$kQw*sRoF'9[9UYP1rDbo_MjY8t$}[:6eXWLl<68곢$ij ]qZv_7/w0tnv:rEx$ >x":hDy~i>dUd;:v\qE4J֮ m{l<[Za]DRΞ!H@h\7ۻ}L`wd<\'̓yUt2dhR?Rȸ—6M߭.hu(D3y%(r2Q$!U2XBx9JAO-;՜axxI**b2DD9ШgB*%,/Mvz(h^sPv (Ϡ0L=rJ)$X 5wk$쯁1xlvéz(8Br vFիݛ׿'TIID/Dv{86%=5Kx=75|ugveX6Cᴾ%#sw"I>_1p-c!uGEQl3Ww9O.g"p$Q] I.g&F(-)~,]"\2&a 0kXǣp\( 9<؆"Kr%Ҥ!qFziLb07H|X"9Ezs_T)x!"gUښQ ۱nh(g#*}Mg\+t/пڃog~:n{۝{ah [R+ l u, endstream endobj 4508 0 obj << /Type /ObjStm /N 100 /First 1035 /Length 4231 /Filter /FlateDecode >> stream x}\emSe:Odm /a7s{fdIXz_u_z5,iZ%ڃ?53fk|%swr[^m_-ev 9Ͱx1(/[/˛scWN^>;˿Mlz _3SxFAG3cԖCt m/5ֿp0טRG[ҌfNӦ7k t{yo5ֺ6Z9nV>_klGֆ}m\n;հ\ޅZhī]# GCsٯ1ԓծ i.|1`^+͖?c99Mk朼怊,~bl61R[ڔsyfjRVhc|`{|qVjh0\B0h[-Â2W円o=svjKXavׅvj3קS[FgHmc\r)X'C]86,pl&6gϟmRjwLm+~~\?r^E"VÕw1 /9ϿOW(Q/ (Mn??>؀W./zZEV+V7Ul@ 0=ŠxE- mCTL6P`( e+ ~f XEʀUݻᅱG Xeƃ^2 Xwxo{ρV/h9-Z@khW0=h[gM2GT=UC)XA50߻lH3 ,F~:+/ * l}6.GԴjE,T3R"`ƸCxs{eO5}q_sBq2F|1XfԮwNy:4R%o;^cwY%x~߹ğR B) 1"2Fx4lA1q5D) ~Ƽ#XuG,Ϻ#g DXG<<Ou'6и$fw!wozjEJ=ɊnXwxGc)ӲV=J>cal[LʩJQDP~_(O4 }>=e1cI# *a7:wWxx?/(G=уWDDe5'*ĶSG}kbgr̄Z&)$>w&J߶>]ΧS Xer-TΠиWD]MN_EOv 3hr-lr m:}*=}6)g:%6)g:ƎSi?J^aEQZ1?W}H]?W@_NJmi$d )o"Mr`P.q\-@hCZYr.OӍpor7'1=fnrbXb[Y5<_|?'775kS> ʡ$ (S~rb W岡Wqmu~<ղ bbVαMVȉ>wbrN5iUpb9ĉy<\b>TN5,`.1O A̧`|JӬUǟ| K%[y^^rMu,*>$ @aˍr I&MI`D~={'7H~5XvrսE)ss&!{-?Ʊ '.=yxb># =1א_75j1 S2 S0||C~csI5AiZrK]OnpO'< f j6n! պ`` ֺYˏu,?@ZwUC̵\_\E̵\_\OEzZV?8A̻\ļ 曘k\&xܫX~lb b\bRs ޚnztS;o9oQdoIFz9bx.d#YB F9AeM]7c=gYZV?8E9搚0x\%Urcqg-> P\ض);79!or*>_ r'I}!(LhY!;#RbHvx%lDOU_N0)wF~9u(N$SX(NF~prK]TtA4AN |߇ļ𛜘O 2)F" b>-b>e`sJ""URWkl* ÜK%K"RIE8CaKu탓|˖ԍ@9l4Rť6sTqÆ '0&N2̥ &*.u9jc0L<22%,0TFʉTFἨ)j̥G7 !\@4).z0yYˏcL_.05%_%DqiB\!Q\PDZ~cA~W_.3˥ dE] E}vX~_j/^9#QB΍Dqa-v-? zB_n=/޵ɑoKD8>ڻN~%PrKP8喠pRŽȹrl;>^~lF:ު U=B瞲<[BI'ZNv0L.Fdvɱ)S6#،tP̜Nݔ R(9(YhdYLy(u17UOMs"'sSnϟmH?yn\ڈ`sʼn)wb.W\;;dYH?6#݉ܜs)܉yļxb=7G^~lFbL\.v<\xs=B xՇc3҃O1||\.X߲S坈K`. 3咷@R.*Z{ ULڌ~vO4a\tܯ.(\oqdLdp=fct>(ԍAȢtld1Ӣ6#،tpL3-(P}(PA247Act?6;no,u&C"zoYbqڍc7RJ7J \uE\\ C IWb=PŁ8#:,5 (.'W!Msl͍:4B}$\HH.> E}d~`QN8#S'9K9KhɢKhɢKhU|pTqʲABӅ(9l,ɢwdQqlH9/5k\cɢK62 [[8v$$S9Iod!AdqTHƱ#$q)Zr$3f HC ] ;$ڒcK22CbYfh! pC&$ؒ ̐7]A9@ 2ФF#R Ʊ'$ de1CH18DFIƱ'$`i9 2͐WAr! eÅyԦdAKt-N4C.1m)ch&euS)Ǧ$[<RM}t8QcXiv4։d]׃Q)c^ԶdےAo}LS_ RƮQRs%ؗ 2M}dx74\A) RF}?QqKf "AA[#t|sˮY<[ؘdԷz_44:I>$&4C3d?6&;hƢ\ݔb~H$Cqڙw& endstream endobj 4701 0 obj << /Producer (pdfTeX-1.40.25) /Author(\376\377\000R\000a\000h\000u\000l\000\040\000S\000a\000t\000i\000j\000a\000;\000\040\000P\000a\000u\000l\000\040\000H\000o\000f\000f\000m\000a\000n\000;\000\040\000Y\000u\000h\000a\000n\000\040\000H\000a\000o\000;\000\040\000A\000u\000s\000t\000i\000n\000\040\000H\000a\000r\000t\000m\000a\000n\000;\000\040\000G\000e\000s\000m\000i\000r\000a\000\040\000M\000o\000l\000l\000a\000;\000\040\000A\000n\000d\000r\000e\000w\000\040\000B\000u\000t\000l\000e\000r\000;\000\040\000T\000i\000m\000\040\000S\000t\000u\000a\000r\000t)/Title(\376\377\000S\000e\000u\000r\000a\000t\000O\000b\000j\000e\000c\000t\000:\000\040\000D\000a\000t\000a\000\040\000S\000t\000r\000u\000c\000t\000u\000r\000e\000s\000\040\000f\000o\000r\000\040\000S\000i\000n\000g\000l\000e\000\040\000C\000e\000l\000l\000\040\000D\000a\000t\000a)/Subject()/Creator(LaTeX with hyperref)/Keywords() /CreationDate (D:20231116163610-05'00') /ModDate (D:20231116163610-05'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.141592653-2.6-1.40.25 (TeX Live 2023) kpathsea version 6.3.5) >> endobj 4609 0 obj << /Type /ObjStm /N 92 /First 945 /Length 3409 /Filter /FlateDecode >> stream xڥ[][ }_q;E: % Iڗ`ob|aͿ/Id皲2@_s%R:ԵyQEΈC : SLU8E*UGi*1OM)uyJeJ#)N#6u$R I%)NHg$ FUiT'Jd(kTNTr Yyt#+'3rD@40_y?j,L%kH`DTJֹFE}Hh$#2JSTMfE$P&EFe%٨N!6U6[>8L-&e\l4 A6~Mgj$)M:sUX>-De$j0˰]L/EH}M3R!Yc !&ފx r-EBbu!qߋM SS![UbɨbVBusg[ L1F%PP b6xDfodXdXY]A*ܞս3&.Hb-ŤL~ )iF<0/ΞmuN]_6wϧ,2{tv6KR*fwIJJzF3F0t%rtvtvtv/>%y~8s_8o.w8o.wY9&#o lQHB=@>5u:dvF08bv9UmLyrƹK{4Pф 6ҽNBH~Nnׇ-'`jtl{=,F[^WF(фbH/^(Fzt/HkeلaR5қ 񪤷m7Hh2@lB ɖa)z39Nlv9Qa]6!u؄f˹ДHlF?f{9 P,6lBHfgH'fF[w5!/=%ř-2N`-N0xLm }|`<ʳ<6,A[دoys>?0r%ۍrv]k.͵WlƶwQ,4O0)zL*fQUuُv!ab eiW zL;XobwL>lv>}PPq>?0ak?G]9yvvܵcu .uأ8@i r2ђtq2]sHGQ2]{+dHI1JWxbww3{Jz^ŞrF1]I]ShZ`.Fkٯo7R+>?aQQQPT# Mp[Tܽoj~F{ zeLwdzeਭ&irCisX/ݝze %+<>8j i&Do1 нBv3X.yŚ+4m}Tip]Lܽ.P;\S]R,/TRJUY>ՙz\XVz\lnutU5FZ|䱹=]@53M:}3hĻK /xҗ. sqB:*;FGO3g;8vțq|58.8Fiqs%O|8 d0$ 2N=^]n?o~]}Wv{:N V aO@<ѿWכ!֗~)S sԞg[՗V w-Zasj0ܼ]_}"E ?"4w/]z{n?_=\mnWu7 @'"!X_']\!ړ։$@@F2af{7_qe{na5k֌dĕug%j[l/_rqHHHn=vpޮnn_,,,݄ظ[o/߭wB=ʼ[888и[]+)ֻUxxx .tgq~}u)SJ>up}gVٍlgGftwՉ +WFE[jO2=R_W=cEZXcU$M87C W["h`feiY?|\<6=|"ČA[|ݟnHv JA>PWD}CCh  > ?_]t NytB) {%h:Bg@1C N~ԟ2 ՔRB*H;A)!j0A)IX~/<|A MC~ KoIWs 6eWk^Ԗ42.WِhDħqq;N]&H,AbOF\Jsg;A L(]r4ҼxӗR']PcS (%A).wR JW#H >fI/ǟhHjQ# >ˏs RHBj@#(ӥebC`l1d_˯-scCau96*|AZǸ2!_꓿2u1n c~uW0ԏ~,Ci~W8R'[PA 2. U÷3˝lA 5ۯ?ēS?N)WB2n Q\f!!CBȸ2$)}7 5d!C wO11.2t'Cit;2! Ad9%e C +=d! '63=bh!C Zȸ52dkzdu%!C b_Jd}|yjZ_Lr+ǵ> ɭ<)kZoALܲ}RiPگϻ޴wxn?07wWخL_~oQLQ== endstream endobj 4702 0 obj << /Type /XRef /Index [0 4703] /Size 4703 /W [1 3 1] /Root 4700 0 R /Info 4701 0 R /ID [ ] /Length 10889 /Filter /FlateDecode >> stream x%icowzzf4Y{z}zM3=}ճ4I]&#ŽP<-2[uW(a0Cv) kt${IRKRTJ32v'ZwZi7j4G Y(,֪+irjo5WJjo4JkՐS{Js U{RsWFؘNe՞k&j4'`[`k'`Gǚ;`VڨHsVۯPsU;@sWv_Lァy< GNJQ8q8I8v]iȫRyΪ=VќsjԊ8UmZ\LFg6]׼Վ]ӼWΩ]Ռ/>]֌/4 bcnィ+AjkjOgGjia"*ʣj":;]j4}Ps~RqB3|Q{ îQ;>M -i#:bF퐚-ԮTE}qZIM}qǦ&~Qg_̩:Z>/W;WSg_ܨvUM[7jξ8|lE}qڤNM}qZtX|1S-:vXn{jjնj߯=ȱAxfCjYmUۤw j5d]XMW{^S:o[>XϩźZW,Weѣ/=Siꍋn zU-j4uj#:bQ-6 +5uj/"R:ⰳ\\Sg_y8.-z(싏e4u'jբßb.v,iM}ZB:+mj)M}PʺlA}f?fE} cξE0xp)+6(OJ;Q-Z^dȾej:S ʫkjjhfa`ڥ&] 95{+5V/RsWs}6L0+(4'`#S-0GٌN} xvًgijjjj4~5{}0Ya<֫< G< Ԏ<'< .< yX74PEhN95{lQզԦ5/EXuKpY^2{M jBW5?xI,f_hMWUl1^ԌqGZ|Xl|5Cz9b̞ 񑈈Jd(8FN#|OIj!ߍ(F|dM ;lE{AeAG׷8 #QXcVJ*X 9Xka aLf[alvn{a0 #pq8'< WۭNR I^9wQ'/8wjk)]t;Ǭk`\сz8g[G#Cv9 l#f v,Lva _XGnyaLm{ N@:ڶ/^p.% W*\0 6-c3pnC8Nucľ' ޅ{px O)<`5Җ+.G_ ~`+tTcϾ)`Tou>x8V:nWQj\j\+6]4]3qEVDU\ū\$ui,^B]޶r`ZaŸqKpV%x*›}rvϺ{u6P߷uݢmq4'%=eki٣ !{\7˞= e5P7I'+e4ǢG |gG#N2 2N2&2N32Y %)INIrJSrhZD$ 9KIϯEIN*ZIJV!k% +IIIJJԖn%XD$*%Q)JITJRıں;am_D$*%Q)JITJRuΛvh; ،t8py@N&I埋تt!C|X+`#`wtQ-Ig7/[t#9VNaCWmA:d@A'6Pv8Qg".'/|o */*~}s.Iuѱ HDG":ё uĢ!=s?I?K0t# aCG:A:w>8 ԯXt~[/c3Nf20 @Y+`%dav0RX &` 8Ca=~p&73 4LRh|a8 8׹o^0=MlutGq)5208 P.A \X4p  >fnau 1<|1^9{d .ނWS3`4r<.qQGp@57ė}28(od? @P0W.x0, ea( CYP0, ea( CY\@.IXEDZ@PE,e(@Y"P]+@Y"Pf|4Iߋ0, eė/_&L|r\cl@#ƷO/_6\6ںlrQ28LfȬY-M!}L= y$wcήuc`n ݝ$o~"! ]tReMQۥKm.]jv'bKh.]Bv ]jW]ǓoŢ2et.]~vL.]zlu&X]~vPtwc_{Go[M,^]zw.]vtƢĢvI%Kr.ݘ 01mʇa\g0u/Yc`(ԩTbh51V&W_1̧'!^꧶m`P~*ĻT|KSu3`{j_kcQ0~>uO$`ga $Y,"=u5 - .`O݅{pBw\qM uiſI}s|OJ?/j!FKcBXx7<:>'_;n>yy9_1_$;opkÿ5a!I~]'~> [߉"0/D`/y9? Q̳?<ϋiy A<8<.0>H`yyya\gvt7+"0/"0/"0/OAW6ܱ.g_ FLH'y3бh8q@๋&ɯ:2x\p9ro-* _f4 $Es I-*X k`-ĸz9Iؔ$񣱀ͰpM. {`/pN)8 y8L8q8 q%⫝H;bRbz%0)504l~L1z- w.܃$1^kx|OWusyViM[QcjrXs m-V[Xm(k N,Ֆv|m"EEK6Ze-ZAL ۓ$ob~y-ZGFc+f؊9c4bXآEcG+IpV[Xm8`|$?j[Xm[o-~[Xm}LI#_MYWT'C$EOr*XK^N҇1^vNX7N82iD{r3l Z{a0 #`|W&OI]'pBdaWku/eW\i7!&i79wb>4b6_ 7ܛ| 17/TNĢ͛4o#7L M:sΥe`ۋis.Betusuzn%:j`un=ӗ\\hIzcQ;Gs0 #t9B#t9B̅ۓ/X(sLB#t9B+l܅$}Gby:Gs"07α:g6sw-T,戚vμ9j稝Ť0*IZ1=`!8 G(p . aӿ?< :LCb p+g:qn >@L~ _+|Z63hlؠAcԦoIWBc|ƪ$h2pa\n0_!Lh#ykAhc]7cyt7n<#ba7mo ~6moFŽ$3cR ۃ`qƊm@HICJRҐ4o A| VSIf#E![~#or!9 7~-_ 7o"0e$$! h|Mo<_H%&e`9Ur`b[flq@nbo!I͵ @L;?&g32&gi♓aNts2&g1#s%,>坹WaF:K;p˘y<'n&gf[xm_|B| :e&0p6|L]dp9,48:Ixע%tYBg %tYBg gvg_9>p,q@lE;xqw: 1Y.gr3{>I2E,y^|&,/>fc6|08Hepvx(HaYaYYy\r٤f'۱jgm$Ihs45# 6lMΛk@olM}Ic&M46ilؤIcƦ4&)ͱddY8j/\6lr$_6!fe7lreSlƽGƒcfܛ!͸#f܇/4 m$9 7Mmds&)MR6$#k>ǧӤIO&=MVe38ESo !{_'#_b&Ͱ3yilad1l" #Q0wb X YX߉5za6AH=ca lvnLA8cpCSpp΂ya%#?2\3w5&CfčdxKq}pCpcx&KO<^1=| > ULL ~+V]a9mW_Bw +tWlHFjVVP[BmJL$$WH\!Br +$WHPVOFO]!Br +$W.%Bm j+VCʅd +qSP[y[xV+|T*Ī=>z|ы\V'#w.>M*rPIA"*QDT$"#G^O:{zmp%yk{k{Rғd˿cj=V{Xcj=V{Xcjqu{n=V{1=9o=~{oߞ{ztݞ;z麽iM܋tݞۣGYe=z(Q֣GY/v?lMF޻d?(,1X+`%daX:X`#&Ͱ6;`'ݰ>`!8 G(pN)8 y8ga A2\p 4anM܅{pCx Gah:w: a20 $T2w5Oa,Ր5za6l-v;a=~8pa8GpNi8 Sp p.E \kp3pn- w.܃#x O)<^+x o->' _+|n\^0!/ 1g_fDk27,^QXcVJȂ9Ӧ#L` u`@kzD4=\iÙ[`+nz;쀝 L{ӆ3!pmڈQ8F3OӧPt xL 6(:}NiO_p5fkNlp̰ &Nў61cp)nzvg x 5. >C ǯ-\0G"E΋9/r^y"E΋9/r^y"E΋9/r^y"E΋9/r^y"E΋9/r^y"E΋9/r^y"E΋9/r^y"EMF,Vd7 lo4E(E(@Q"PE(E(@Q"PE(E(@Q"PE(E(@Q"PE(}_/}@_"E/}@_"E/}@_"E/}@_"E/}@_"E/}@_"E/}@_"E/}@_}_}KD>}9sy>}9sy>}9sy>}9sy>nNXK/qK/qK/91%Η8_|).pE9_|)uΗ8_9_|%Ηb>0K/M/Ń b K%#P2i-YkK[Q֖wȿR]F2Ik4eIUƒky2N"V&tA!C|gbW-JaYd3_JFsCYp/mT,u)V˂G<[j1pGM>υ(xpWaw<\xO*x0V W*x"dsC XÂ!,x6da'x:ea7xTZ-/+xb[x8b2 [Yp~$ V0ypN'V ZZ+xZ Yɂg < fO]+xf Ypo_j: WpC@  Sg<p #include #include #include #include #include using namespace Rcpp; Eigen::SparseMatrix RowMergeMatricesList( List mat_list, List mat_rownames, std::vector all_rownames ); template std::vector sort_indexes(const std::vector &v); List GraphToNeighborHelper(Eigen::SparseMatrix mat); SeuratObject/src/valid_pointer.c0000644000176200001440000000024714473173564016457 0ustar liggesusers#include // helper to determine if external c++ pointer is valid SEXP isnull(SEXP pointer) { return Rf_ScalarLogical(!R_ExternalPtrAddr(pointer)); } SeuratObject/src/data_manipulation.cpp0000644000176200001440000000726314473173564017656 0ustar liggesusers#include #include #include #include #include #include using namespace Rcpp; // [[Rcpp::depends(RcppEigen)]] typedef Eigen::Triplet T; template std::vector sort_indexes(const std::vector &v) { // initialize original index locations std::vector idx(v.size()); std::iota(idx.begin(), idx.end(), 0); std::stable_sort(idx.begin(), idx.end(), [&v](size_t i1, size_t i2) {return v[i1] < v[i2];}); return idx; } // [[Rcpp::export(rng = false) // [[Rcpp::export(rng = false)]] List GraphToNeighborHelper(Eigen::SparseMatrix mat) { mat = mat.transpose(); //determine the number of neighbors int n = 0; for(Eigen::SparseMatrix::InnerIterator it(mat, 0); it; ++it) { n += 1; } Eigen::MatrixXd nn_idx(mat.rows(), n); Eigen::MatrixXd nn_dist(mat.rows(), n); for (int k=0; k row_idx; std::vector row_dist; row_idx.reserve(n); row_dist.reserve(n); for (Eigen::SparseMatrix::InnerIterator it(mat,k); it; ++it) { if (n_k > (n-1)) { Rcpp::stop("Not all cells have an equal number of neighbors."); } row_idx.push_back(it.row() + 1); row_dist.push_back(it.value()); n_k += 1; } if (n_k != n) { Rcpp::Rcout << n << ":::" << n_k << std::endl; Rcpp::stop("Not all cells have an equal number of neighbors."); } //order the idx based on dist std::vector idx_order = sort_indexes(row_dist); for(int i = 0; i < n; ++i) { nn_idx(k, i) = row_idx[idx_order[i]]; nn_dist(k, i) = row_dist[idx_order[i]]; } } List neighbors = List::create(nn_idx, nn_dist); return(neighbors); } // [[Rcpp::export(rng = false)]] Eigen::SparseMatrix RowMergeMatricesList( List mat_list, List mat_rownames, std::vector all_rownames ) { // Convert Rcpp lists to c++ vectors std::vector> mat_vec; mat_vec.reserve(mat_list.size()); std::vector> rownames_vec; rownames_vec.reserve(mat_rownames.size()); std::vector> map_vec; map_vec.reserve(mat_list.size()); int num_cols = 0; int num_nZero = 0; // offsets keep track of which column to add in to std::vector offsets; for (unsigned int i = 0; i < mat_list.size(); i++) { mat_vec.emplace_back(Rcpp::as>(mat_list.at(i))); rownames_vec.push_back(mat_rownames[i]); // Set up hash maps for rowname based lookup std::unordered_map mat_map; for (unsigned int j = 0; j < rownames_vec[i].size(); j++) { mat_map[rownames_vec[i][j]] = j; } map_vec.emplace_back(mat_map); offsets.push_back(num_cols); num_cols += mat_vec[i].cols(); num_nZero += mat_vec[i].nonZeros(); } // set up tripletList for new matrix creation std::vector tripletList; int num_rows = all_rownames.size(); tripletList.reserve(num_nZero); // loop over all rows and add nonzero entries to tripletList for(int i = 0; i < num_rows; i++) { std::string key = all_rownames[i]; for(int j = 0; j < mat_vec.size(); j++) { if (map_vec[j].count(key)) { for(Eigen::SparseMatrix::InnerIterator it1(mat_vec[j], map_vec[j][key]); it1; ++it1){ tripletList.emplace_back(i, it1.col() + offsets[j], it1.value()); } } } } Eigen::SparseMatrix combined_mat(num_rows, num_cols); combined_mat.setFromTriplets(tripletList.begin(), tripletList.end()); return combined_mat; } SeuratObject/src/RcppExports.cpp0000644000176200001440000000357614473174305016453 0ustar liggesusers// Generated by using Rcpp::compileAttributes() -> do not edit by hand // Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 #include #include using namespace Rcpp; #ifdef RCPP_USE_GLOBAL_ROSTREAM Rcpp::Rostream& Rcpp::Rcout = Rcpp::Rcpp_cout_get(); Rcpp::Rostream& Rcpp::Rcerr = Rcpp::Rcpp_cerr_get(); #endif // GraphToNeighborHelper List GraphToNeighborHelper(Eigen::SparseMatrix mat); RcppExport SEXP _SeuratObject_GraphToNeighborHelper(SEXP matSEXP) { BEGIN_RCPP Rcpp::RObject rcpp_result_gen; Rcpp::traits::input_parameter< Eigen::SparseMatrix >::type mat(matSEXP); rcpp_result_gen = Rcpp::wrap(GraphToNeighborHelper(mat)); return rcpp_result_gen; END_RCPP } // RowMergeMatricesList Eigen::SparseMatrix RowMergeMatricesList(List mat_list, List mat_rownames, std::vector all_rownames); RcppExport SEXP _SeuratObject_RowMergeMatricesList(SEXP mat_listSEXP, SEXP mat_rownamesSEXP, SEXP all_rownamesSEXP) { BEGIN_RCPP Rcpp::RObject rcpp_result_gen; Rcpp::traits::input_parameter< List >::type mat_list(mat_listSEXP); Rcpp::traits::input_parameter< List >::type mat_rownames(mat_rownamesSEXP); Rcpp::traits::input_parameter< std::vector >::type all_rownames(all_rownamesSEXP); rcpp_result_gen = Rcpp::wrap(RowMergeMatricesList(mat_list, mat_rownames, all_rownames)); return rcpp_result_gen; END_RCPP } RcppExport SEXP isnull(SEXP); static const R_CallMethodDef CallEntries[] = { {"_SeuratObject_GraphToNeighborHelper", (DL_FUNC) &_SeuratObject_GraphToNeighborHelper, 1}, {"_SeuratObject_RowMergeMatricesList", (DL_FUNC) &_SeuratObject_RowMergeMatricesList, 3}, {"isnull", (DL_FUNC) &isnull, 1}, {NULL, NULL, 0} }; RcppExport void R_init_SeuratObject(DllInfo *dll) { R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); R_useDynamicSymbols(dll, FALSE); } SeuratObject/R/0000755000176200001440000000000014525215076013054 5ustar liggesusersSeuratObject/R/centroids.R0000644000176200001440000003172314520004201015154 0ustar liggesusers#' @include zzz.R #' @include generics.R #' @importFrom methods as callNextMethod #' @importClassesFrom sp SpatialPoints #' NULL #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Class definitions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' The \code{Centroids} Class #' #' @slot cells (\code{\link[base:character]{character [n]}}) A vector of cell #' names; there should be as many cell names as there are points and no #' duplicate names #' @slot nsides (\code{\link[base:integer]{integer [1L]}}) The number of sides #' to draw when plotting centroids; must be either \code{0L} for circles or #' greater than 3 #' @slot radius (\code{\link[base:numeric]{numeric [1L]}}) The radius of the #' shape when plotting the centroids #' @slot theta (\code{\link[base:numeric]{numeric [1L]}}) The angle in degrees #' to adjust the shape when plotting the centroids #' #' @family segmentation #' @templateVar cls Centroids #' @template seealso-methods #' setClass( Class = 'Centroids', contains = 'SpatialPoints', slots = list( cells = 'character', nsides = 'integer', radius = 'numeric', theta = 'numeric' ) ) #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Functions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for Seurat-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' \code{Centroids} Methods #' #' Methods for \code{\link[SeuratObject:Centroids-class]{Centroids}} objects #' #' @param x,object A \code{\link[SeuratObject:Centroids-class]{Centroids}} #' object #' @param i,cells A vector of cells to keep; if \code{NULL}, defaults #' to all cells #' @param j,drop Ignored #' @param ... Arguments passed to other methods #' #' @name Centroids-methods #' @rdname Centroids-methods #' #' @seealso \code{\link{Centroids-class}} #' #' @family segmentation #' NULL #' #' @rdname Centroids-methods #' @method Cells Centroids #' @export #' Cells.Centroids <- function(x, ...) { return(slot(object = x, name = 'cells')) } #' @importFrom sp SpatialPoints #' #' @method CreateCentroids default #' @export #' CreateCentroids.default <- function( coords, nsides = Inf, radius = NULL, theta = 0L ) { cnames <- c('x', 'y') if (ncol(x = coords) >= 3) { cnames <- append(x = cnames, values = 'cell') } idx <- NameIndex(x = coords, names = cnames, MARGIN = 2L) cells <- if ('cell' %in% names(x = idx)) { as.character(x = coords[, idx[['cell']], drop = TRUE]) } else { rownames(x = coords) } coords <- as.matrix(x = coords[, idx[c('x', 'y'), drop = FALSE]]) colnames(x = coords) <- c('x', 'y') rownames(x = coords) <- NULL if (is.infinite(x = nsides)) { nsides <- 0L } radius <- radius %||% .AutoRadius(coords = coords) obj <- as(object = SpatialPoints(coords = coords), Class = 'Centroids') slot(object = obj, name = 'cells') <- cells slot(object = obj, name = 'nsides') <- as.integer(x = nsides) slot(object = obj, name = 'radius') <- as.numeric(x = radius) slot(object = obj, name = 'theta') <- as.numeric(x = theta) validObject(object = obj) return(obj) } #' @method CreateCentroids Centroids #' @export #' CreateCentroids.Centroids <- function( coords, nsides = NULL, radius = NULL, theta = NULL ) { return(CreateCentroids( coords = GetTissueCoordinates(object = coords), nsides = nsides %||% length(x = coords), radius = radius %||% Radius(object = coords), theta = theta %||% Theta(object = coords) )) } #' @method Crop Centroids #' @export #' Crop.Centroids <- .Crop #' @details \code{GetTissueCoordinates}: Get cell spatial coordinates #' #' @param full Expand the coordinates to the full polygon #' #' @return \code{GetTissueCoordinates}: A data frame with three columns: #' \itemize{ #' \item \dQuote{\code{x}}: the x-coordinate #' \item \dQuote{\code{y}}: the y-coordinate #' \item \dQuote{\code{cell}}: the cell name #' } #' If \code{full} is \code{TRUE}, then each coordinate will indicate a vertex #' for the cell polygon; otherwise, each coordinate will indicate a centroid #' for the cell #' #' @importFrom sp coordinates #' #' @rdname Centroids-methods #' @method GetTissueCoordinates Centroids #' @export #' GetTissueCoordinates.Centroids <- function(object, full = TRUE, ...) { coords <- as.data.frame(x = coordinates(obj = object)) colnames(x = coords) <- c('x', 'y') coords$cell <- Cells(x = object) if (isTRUE(x = full) && is.finite(x = object)) { ct <- mapply( FUN = PolyVtx, xc = coords$x, yc = coords$y, MoreArgs = list( n = length(x = object), r = Radius(object = object), t1 = Theta(object = object) ) ) xt <- vector(mode = 'list', length = length(x = ct) / 2L) xi <- 1L for (i in seq.int(from = 1L, to = length(x = ct), by = 2L)) { xt[[xi]] <- data.frame( x = ct[[i]], y = ct[[i + 1L]], cell = coords$cell[xi], stringsAsFactors = FALSE ) xi <- xi + 1L } coords <- do.call(what = 'rbind', args = xt) } return(coords) } #' @details \code{Radius}: Get the centroid radius #' #' @return \code{Radius} The radius of the centroids #' #' @rdname Centroids-methods #' @method Radius Centroids #' @export #' Radius.Centroids <- function(object) { return(slot(object = object, name = 'radius')) } #' @details \code{RenameCells}: Update cell names #' #' @inheritParams RenameCells #' #' @return \code{RenameCells}: \code{object} with the cells renamed to #' \code{new.names} #' #' @rdname Centroids-methods #' @method RenameCells Centroids #' @export #' RenameCells.Centroids <- function(object, new.names = NULL, ...) { if (is.null(x = new.names)) { return(object) } new.names <- make.unique(names = new.names) if (length(x = new.names) != length(x = Cells(x = object))) { stop("Cannot partially rename centroid cells", call. = FALSE) } slot(object = object, name = 'cells') <- new.names return(object) } #' @details \code{Theta}: Get the offset angle #' #' @return \code{Theta}: The offset angle in degrees #' #' @rdname Centroids-methods #' @method Theta Centroids #' @export #' Theta.Centroids <- function(object) { return(slot(object = object, name = 'theta')) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for R-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' @details \code{is.finite}, \code{is.infinite}: Test to see if the centroids #' are circular or polygonal #' #' @return \code{is.finite}: \code{TRUE} if the centroids are polygonal, #' \code{FALSE} if circular #' #' @rdname Centroids-methods #' @method is.finite Centroids #' @export #' is.finite.Centroids <- .FiniteCentroids #' @return \code{is.infinite}: The opposite of \code{is.finite} #' #' @rdname Centroids-methods #' @method is.infinite Centroids #' @export #' is.infinite.Centroids <- Negate(f = .FiniteCentroids) #' @details \code{length}: Get the number of sides for the polygonal centroid #' #' @return \code{length}: \code{0} if the centroids are circular, otherwise the #' number of sides of the polygonal centroid #' #' @rdname Centroids-methods #' @method length Centroids #' @export #' length.Centroids <- function(x) { return(slot(object = x, name = 'nsides')) } #' @template method-lengths #' #' @rdname Centroids-methods #' @method lengths Centroids #' @export #' lengths.Centroids <- function(x, use.names = TRUE) { return(rle(x = Cells(x = x))) } #' @details \code{subset}, \code{[}: Subset a \code{Centroids} object to #' certain cells #' #' @return \code{subset}, \code{[}: \code{x} subsetted to the cells specified #' by \code{cells}/\code{i} #' #' @rdname Centroids-methods #' @method subset Centroids #' @export #' subset.Centroids <- function(x, cells = NULL, ...) { args <- list(...) if (is.null(x = cells)) { return(x) } if (is.numeric(x = cells)) { cells <- Cells(x = x)[cells] cells <- cells[!is.na(x = cells)] } cells <- MatchCells(new = Cells(x = x), orig = cells, ordered = TRUE) if (!length(x = cells)) { stop("None of the requested cells found") } return(CreateCentroids( coords = GetTissueCoordinates(object = x)[cells, ], nsides = args$nsides %||% length(x = x), radius = args$radius %||% Radius(object = x), theta = args$theta %||% Theta(object = x) )) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Internal #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # S4 methods #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' @rdname Centroids-methods #' setMethod( f = '[', signature = c(x = 'Centroids', i = 'character'), definition = function(x, i, j, ..., drop = TRUE) { i <- MatchCells(new = Cells(x = x), orig = i, ordered = TRUE) return(x[i, drop = drop, ...]) } ) #' @rdname Centroids-methods #' setMethod( f = '[', signature = c(x = 'Centroids', i = 'numeric'), definition = function(x, i, j, ..., drop = TRUE) { info <- list( nsides = length(x = x), radius = Radius(object = x), theta = Theta(object = x) ) cells <- Cells(x = x)[i] cells <- cells[!is.na(x = cells)] x <- callNextMethod() for (n in names(x = info)) { slot(object = x, name = n) <- info[[n]] } slot(object = x, name = 'cells') <- cells validObject(object = x) return(x) } ) setMethod( f = 'over', signature = c(x = 'Centroids', y = 'SpatialPolygons'), definition = function(x, y, returnList = FALSE, fn = NULL, ...) { deprecate_stop( when = '5.0.0', what = 'over()', details = "Future integration with `sf` is on the roadmap with no current ETA" ) check_installed(pkg = 'sf') return(over( x = as(object = x, Class = 'sf'), y = as(object = y, Class = 'sf'), returnList = returnList, fn = fn, ... )) } ) #' @rdname Overlay #' @export #' setMethod( f = 'Overlay', signature = c(x = 'Centroids', y = 'SpatialPolygons'), definition = function(x, y, invert = FALSE, ...) { check_installed(pkg = 'sf', reason = 'to overlay spatial information') idx <- sf::st_intersects( x = as(object = x, Class = 'sf'), y = as(object = y, Class = 'sf'), sparse = FALSE ) idx <- which(idx) names_in_sf_object1 <- if (!is.null(x = row.names(x = x))) { row.names(x = x)[idx] } else { x$id[idx] } idx <- setNames( object = rep(x = TRUE, length(x = idx)), nm = names_in_sf_object1 ) if (!length(x = idx)) { warn(message = "The selected region does not contain any cell centroids") return(NULL) } idx <- sort(x = as.integer(x = names(x = idx))) if (isTRUE(x = invert)) { idx <- -idx } return(x[idx]) } ) #' @template method-show #' #' @rdname Centroids-methods #' setMethod( f = 'show', signature = c(object = 'Centroids'), definition = function(object) { cat("Spatial centroids for", length(x = Cells(x = object)), "cells\n") cat( "", ifelse( test = length(x = object) == 0L, yes = "Circular", no = paste0(length(x = object), '-sided') ), "spots\n" ) cat(" Radius:", Radius(object = object), '\n') cat(" Offset angle:", Theta(object = object), "degrees\n") return(invisible(x = NULL)) } ) setValidity( Class = 'Centroids', method = function(object) { if (isFALSE(x = getOption(x = "Seurat.object.validate", default = TRUE))) { warn( message = paste("Not validating", class(x = object)[1L], "objects"), class = 'validationWarning' ) return(TRUE) } valid <- NULL # Check cell names cells <- Cells(x = object) ucells <- Filter(f = nchar, x = unique(x = cells)) if (length(x = ucells) != length(x = cells)) { valid <- c( valid, "'cells' must be a vector of unique cell names with one name for every coordinate" ) } if (length(x = cells) != nrow(x = slot(object = object, name = 'coords'))) { valid <- c( valid, "the length of 'cells' must equal the number of rows in 'coords'" ) } if (!is.null(x = rownames(x = slot(object = object, name = 'coords')))) { valid <- c(valid, "'coords' must not have any rownames") } # Check nsides nsides <- length(x = object) if (nsides < 0L || nsides %in% seq.int(from = 1L, to = 2L)) { valid <- c( valid, "'nsides' must be either 0 or greater than or equal to 3" ) } # Check radius if (Radius(object = object) <= 0) { valid <- c(valid, "'radius' must be greater than 0") } # Check theta theta <- Theta(object = object) if (theta < 0 || theta > 360) { valid <- c(valid, "'theta must be between 0 and 360") } return(valid %||% TRUE) } ) SeuratObject/R/jackstraw.R0000644000176200001440000001131214473173564015175 0ustar liggesusers#' @include zzz.R #' @include generics.R #' @importFrom methods slot slot<- slotNames #' NULL #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Class definitions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' The JackStrawData Class #' #' The JackStrawData is used to store the results of a JackStraw computation. #' #' @slot empirical.p.values Empirical p-values #' @slot fake.reduction.scores Fake reduction scores #' @slot empirical.p.values.full Empirical p-values on full #' @slot overall.p.values Overall p-values from ScoreJackStraw #' #' @name JackStrawData-class #' @rdname JackStrawData-class #' @exportClass JackStrawData #' JackStrawData <- setClass( Class = "JackStrawData", slots = list( empirical.p.values = "matrix", fake.reduction.scores = "matrix", empirical.p.values.full = "matrix", overall.p.values = "matrix" ) ) #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Functions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for Seurat-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' @rdname JS #' @export #' @method JS JackStrawData #' JS.JackStrawData <- function(object, slot, ...) { CheckDots(...) slot <- switch( EXPR = slot, 'empirical' = 'empirical.p.values', 'fake' = 'fake.reduction.scores', 'full' = 'empirical.p.values.full', 'overall' = 'overall.p.values', slot ) return(slot(object = object, name = slot)) } #' @rdname JS #' @export #' @method JS<- JackStrawData #' "JS<-.JackStrawData" <- function(object, slot, ..., value) { CheckDots(...) slot <- switch( EXPR = slot, 'empirical' = 'empirical.p.values', 'fake' = 'fake.reduction.scores', 'full' = 'empirical.p.values.full', 'overall' = 'overall.p.values', slot ) slot(object = object, name = slot) <- value return(object) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for R-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' \code{JackStrawData} Methods #' #' Methods for \code{\link{JackStrawData}} objects for generics defined in #' other packages #' #' @param x,object A \code{\link{JackStrawData}} object #' @param ... Ignored #' #' @name JackStrawData-methods #' @rdname JackStrawData-methods #' #' @concept jackstraw #' NULL #' @describeIn JackStrawData-methods Autocompletion for \code{$} access on a #' \code{JackStrawData} object #' #' @inheritParams utils::.DollarNames #' #' @importFrom utils .DollarNames #' @export #' @method .DollarNames JackStrawData #' ".DollarNames.JackStrawData" <- function(x, pattern = '') { slotnames <- as.list(x = slotNames(x = x)) names(x = slotnames) <- unlist(x = slotnames) return(.DollarNames(x = slotnames, pattern = pattern)) } #' @describeIn JackStrawData-methods Access data from a \code{JackStrawData} #' object #' #' @param i A \code{JackStrawData} slot name #' #' @return \code{$}: Slot \code{i} from \code{x} #' @export #' "$.JackStrawData" <- function(x, i, ...) { return(slot(object = x, name = i)) } #' @describeIn JackStrawData-methods Have empirical p-values for a #' \code{JackStrawData} object been calculated #' #' @return \code{as.logical}: \code{TRUE} if empirical p-values have been #' calculated otherwise \code{FALSE} #' #' @export #' @method as.logical JackStrawData #' as.logical.JackStrawData <- function(x, ...) { CheckDots(...) empP <- JS(object = x, slot = 'empirical') return(!(all(dim(x = empP) == 0) || all(is.na(x = empP)))) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # S4 methods #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' @describeIn JackStrawData-methods Overview of a \code{JackStrawData} object #' #' @return \code{show}: Prints summary to \code{\link[base]{stdout}} and #' invisibly returns \code{NULL} #' #' @importFrom utils head #' @importFrom methods show #' #' @export #' setMethod( f = 'show', signature = 'JackStrawData', definition = function(object) { empp <- object$empirical.p.values scored <- object$overall.p.values cat( "A JackStrawData object simulated on", nrow(x = empp), "features for", ncol(x = empp), "dimensions.\n", "Scored for:", nrow(x = scored), "dimensions.\n" ) return(invisible(x = NULL)) } ) #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Internal #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% SeuratObject/R/utils.R0000644000176200001440000021104114525215076014336 0ustar liggesusers#' @include zzz.R #' @include generics.R #' @include centroids.R #' @include segmentation.R #' @importFrom Rcpp evalCpp #' @importFrom methods as setAs #' NULL #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Functions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' Set If or If Not \code{NULL} #' #' Set a default value depending on if an object is \code{NULL} #' #' @param x An object to test #' @param y A default value #' #' @return For \code{\%||\%}: \code{y} if \code{x} is \code{NULL}; #' otherwise \code{x} #' #' @importFrom rlang %||% #' #' @name set-if-null #' @rdname set-if-null #' #' @author For \code{\%||\%}: \pkg{rlang} developers #' #' @seealso \code{\link[rlang:op-null-default]{rlang::\%||\%}} #' #' @export #' #' @concept utils #' #' @examples #' # Set if NULL #' 1 %||% 2 #' NULL %||% 2 #' `%||%` <- rlang::`%||%` #' @rdname set-if-null #' #' @return For \code{\%iff\%}: \code{y} if \code{x} is \strong{not} #' \code{NULL}; otherwise \code{x} #' #' @importFrom rlang is_null #' #' @export #' #' @examples #' # Set if *not* NULL #' 1 %iff% 2 #' NULL %iff% 2 #' `%iff%` <- function(x, y) { if (!is_null(x = x)) { return(y) } return(x) } #' Set If or If Not \code{NA} #' #' Set a default value depending on if an object is \code{\link[base]{NA}} #' #' @inheritParams set-if-null #' #' @return For \code{\%NA\%}: \code{y} if \code{x} is \code{\link[base]{NA}}; #' otherwise \code{x} #' #' @name set-if-na #' @rdname set-if-na #' #' @importFrom rlang is_na #' #' @keywords internal #' #' @export #' #' @concept utils #' #' @examples #' # Set if NA #' 1 %NA% 2 #' NA %NA% 2 #' `%NA%` <- function(x, y) { if (is_na(x = x)) { return(y) } return(x) } #' @rdname set-if-na #' #' @export #' `%na%` <- `%NA%` #' @return For \code{\%!NA\%}: \code{y} if \code{x} is \strong{not} #' \code{\link[base]{NA}}; otherwise \code{x} #' #' @rdname set-if-na #' #' @importFrom rlang is_na #' #' @export #' #' @examples #' # Set if *not* NA #' 1 %!NA% 2 #' NA %!NA% 2 #' `%!NA%` <- function(x, y) { if (is_na(x = x)) { return(x) } return(y) } #' @rdname set-if-na #' #' @export #' `%!na%` <- `%!NA%` #' \pkg{BPCells} Matrix Mode #' #' Get the mode (on-disk, in-memory) of an \code{IterableMatrix} object #' from \pkg{BPCells} #' #' @param object An \code{IterableMatrix} #' @param simplify Return \dQuote{\code{disk}} for on-disk matrices #' #' @return One of the following, depending on the mode of \code{object}: #' \itemize{ #' \item \dQuote{\code{memory}} #' \item \dQuote{\code{file}} #' \item \dQuote{\code{directory}} #' } #' If \code{simplify} is \code{TRUE}, returns \dQuote{\code{disk}} instead of #' \dQuote{\code{file}} or \dQuote{\code{directory}} #' #' @keywords internal #' #' @export #' .BPMatrixMode <- function(object, simplify = FALSE) { check_installed(pkg = 'BPCells', reason = 'for working with BPCells') if (!inherits(x = object, what = 'IterableMatrix')) { return(NULL) } stopifnot(rlang::is_bare_logical(x = simplify, n = 1L)) # Get a vector of all the slots in all sub-matrices slots <- Reduce( f = union, x = lapply( X = BPCells::all_matrix_inputs(object), FUN = \(x) methods::slotNames(x = methods::getClass(Class = class(x = x))) ) ) # Figure out if any sub-matrix points to a directory or a file path type <- c(path = FALSE, dir = FALSE) for (s in slots) { if (s %in% names(x = type)) { type[s] <- TRUE } } # If no matrix points to a directory or file, it's an in-memory one if (!any(type)) { return('memory') } # If any matrix points to a directory or file, it's an on-disk matrix if (isTRUE(x = simplify) && any(type)) { return("disk") } # Get the exact type; there should only be one return(c(path = 'file', dir = 'directory')[[names(x = type)[type]]]) } #' Identify Object Collections #' #' Find all collection (named lists) slots in an S4 object #' #' @inheritParams .Contains #' @param exclude A character vector of slot names to exclude #' @param ... Arguments passed to \code{\link{IsNamedList}} #' #' @return A character vector of names of collection slots #' #' @importFrom methods slotNames #' #' @keywords internal #' #' @export #' #' @family subobjects #' @concept utils #' #' @examples #' .Collections(pbmc_small) #' .Collections <- function(object, exclude = character(length = 0L), ...) { if (!isS4(object)) { abort(message = "'object' is not an S4 object") } collections <- slotNames(x = object) collections <- Filter( f = function(s) { return(IsNamedList(x = slot(object = object, name = s), ...)) }, x = collections ) if (is.character(x = exclude) && length(x = exclude)) { collections <- setdiff(x = collections, y = exclude) } return(collections) } #' Get Parent S4 Classes #' #' @param object An \link[methods:Classes_Details]{S4} object #' #' @return A vector of class names that \code{object} inherits from #' #' @importFrom methods getClass slot #' #' @keywords internal #' #' @export #' #' @concept utils #' #' @examples #' .Contains(pbmc_small) #' .Contains <- function(object) { if (!isS4(object)) { abort(message = "'object' not an S4 object") } return(names(x = slot( object = getClass(Class = class(x = object)), name = 'contains' ))) } #' Find the Default FOV #' #' Attempts to find the \dQuote{default} FOV using the revamped #' spatial framework #' #' @param object A \code{{Seurat}} object #' #' @return ... #' #' @keywords internal #' #' @export #' #' @concept utils #' .DefaultFOV <- function(object, assay = NULL) { images <- .FilterObjects(object = object, classes.keep = 'FOV') if (!is.null(x = assay)) { assays <- c(assay, DefaultAssay(object = object[[assay]])) images <- Filter( f = function(x) { return(DefaultAssay(object = object[[x]]) %in% assays) }, x = images ) } if (!length(x = images)) { return(NULL) } return(images) } #' Deprecate Functions and Arguments #' #' Provides automatic deprecation and defunctation of functions and arguments; #' #' @inheritParams lifecycle::deprecate_soft #' @inheritDotParams lifecycle::deprecate_soft #' @param pkg Name of package to use for comparison #' @param env,user_env Managed internally by \code{.Deprecate()} #' #' @return Run for its side effect and invisibly returns \code{NULL} #' #' @importFrom rlang ns_env_name #' @importFrom utils packageVersion #' @importFrom lifecycle deprecate_soft deprecate_stop deprecate_warn #' #' @keywords internal #' #' @export #' #' @seealso \code{\link[lifecycle:deprecate_soft]{lifecycle::deprecate_soft}()} #' \code{\link[lifecycle:deprecate_warn]{lifecycle::deprecate_warn}()} #' \code{\link[lifecycle:deprecate_stop]{lifecycle::deprecate_stop}()} #' .Deprecate <- function( when, what, with = NULL, ..., pkg = NULL, env = missing_arg(), user_env = missing_arg() ) { # Figure out current version, rounding up development versions caller <- caller_env() current <- .RoundVersion(current = packageVersion( pkg = ns_env_name(x = caller) )) cv <- paste(current, collapse = '.') # Ensure our 'when' is a valid version wv <- when <- as.character(x = numeric_version(x = when, strict = TRUE)) # If we haven't reached deprecation, exit out silently if (cv < wv) { return(invisible(x = NULL)) } # Figure out if this is a soft deprecation, a warning deprecation, or a defunct when <- unlist(x = strsplit(x = when, split = '\\.')) if (length(x = when) > 4L) { when[4L] <- paste( when[seq.int(from = 4L, to = length(x = when))], collapse = '.' ) when <- when[1:4] } names(x = when) <- c('major', 'minor', 'patch', 'devel')[seq_along(along.with = when)] when <- vapply( X = when, FUN = as.integer, FUN.VALUE = integer(length = 1L), USE.NAMES = TRUE ) diffs <- abs(current - when) if (diffs['major'] >= 1L || diffs['minor'] >= 3L) { deprecate_stop( when = wv, what = what, with = with, env = caller, ... ) } fn <- if (diffs['minor'] >= 1L) { deprecate_warn } else { deprecate_soft } fn( when = wv, what = what, with = with, env = caller, user_env = caller_env(n = 2L), ... ) return(invisible(x = NULL)) } #' Find Subobjects Of A Certain Class #' #' @inheritParams .Collections #' @param classes.keep A vector of classes to keep #' #' @return A vector of object names that are of class \code{classes.keep} #' #' @keywords internal #' #' @export #' #' @family subobjects #' @concept utils #' #' @examples #' .FilterObjects(pbmc_small) #' .FilterObjects(pbmc_small, "Graph") #' .FilterObjects <- function( object, classes.keep = c('Assay', 'StdAssay', 'DimReduc') ) { collections <- .Collections(object = object, exclude = c('misc', 'tools')) subobjects <- unlist(x = lapply( X = collections, FUN = function(x) { return(Filter( f = function(i) { return(inherits( x = slot(object = object, name = x)[[i]], what = classes.keep )) }, x = names(x = slot(object = object, name = x)) )) } )) if (!length(x = subobjects)) { subobjects <- NULL } return(subobjects) } #' Find A Subobject #' #' Determine the slot that a subobject is contained in #' #' @inheritParams .Collections #' @param name Name of subobject to find #' #' @return The name of the slot that contains \code{name}; returns \code{NULL} #' if a subobject named \code{name} cannot be found #' #' @keywords internal #' #' @export #' #' @family subobjects #' @concept utils #' #' @examples #' .FindObject(pbmc_small, "tsne") #' .FindObject <- function(object, name, exclude = c('misc', 'tools')) { collections <- .Collections(object = object, exclude = exclude) object.names <- sapply( X = collections, FUN = function(x) { return(names(x = slot(object = object, name = x))) }, simplify = FALSE, USE.NAMES = TRUE ) object.names <- Filter(f = Negate(f = is.null), x = object.names) for (i in names(x = object.names)) { if (name %in% names(x = slot(object = object, name = i))) { return(i) } } return(NULL) } #' Get a Method #' #' @param fxn Name of a function as a character #' @param cls The class to find a method of \code{fxn} for #' #' @return The method of \code{fxn} for class \code{cls}; if no method found, #' returns the default method. If no default method found; returns \code{NULL} #' #' @importFrom utils getS3method isS3stdGeneric #' @importFrom methods isClass isGeneric selectMethod #' #' @keywords internal #' #' @export #' #' @concept utils #' #' @examples #' .GetMethod('t', 'Matrix') #' .GetMethod('t', 'data.frame') #' .GetMethod <- function(fxn, cls) { if (is.function(x = fxn)) { fxn <- as.character(x = substitute(expr = fxn)) } if (!(isS3stdGeneric(f = fxn) || isGeneric(f = fxn))) { abort(message = paste0("'", fxn, "' is not a generic function")) } default <- NULL if (isGeneric(f = fxn) && isClass(Class = cls[1L])) { method <- selectMethod(f = fxn, signature = cls) if (!inherits(x = method, what = 'derivedDefaultMethod')) { return(slot(object = method, name = '.Data')) } default <- slot(object = method, name = '.Data') } method <- NULL for (i in c(cls, 'default')) { method <- getS3method(f = fxn, class = i, optional = TRUE) if (!is.null(x = method)) { break } } method <- method %||% default if (is.null(x = method)) { abort(message = paste0( "Unable to find a method for '", fxn, "' for '", cls[1L], "' objects" )) } return(method) } #' Propagate a List #' #' @param x A list or character vector #' @param names A vector of names to keep from \code{x} #' @param default A default value for unassigned values of \code{x} #' #' @return A named list where the names are present in both \code{x} and #' \code{names} and the values are either the values from \code{x} or #' \code{default} #' #' @keywords internal #' #' @export #' #' @concept utils #' #' @examples #' .PropagateList("counts", c("RNA", "ADT", "SCT")) #' .PropagateList(c("counts", "data"), c("RNA", "ADT", "SCT")) #' .PropagateList("ADT", c("RNA", "ADT", "SCT")) #' .PropagateList(c("RNA", "SCT"), c("RNA", "ADT", "SCT")) #' .PropagateList(c("RNA", ADT = "counts"), c("RNA", "ADT", "SCT")) #' .PropagateList(list(SCT = c("counts", "data"), ADT = "counts"), c("RNA", "ADT", "SCT")) #' .PropagateList(list(SCT = c("counts", "data"), "ADT"), c("RNA", "ADT", "SCT")) #' .PropagateList <- function(x, names, default = NA) { # `names` must be a character vector if (!is_bare_character(x = names)) { abort(message = "'names' must be a character vector") } # `x` must be a list or character vector if (!(is_bare_list(x = x) || is_bare_character(x = x))) { abort(message = "'x' must be either a list or character vector") } # `x` cannot be empty if (!length(x = x)) { abort(message = "'x' cannot be empty") } # `x` is a character vector if (is_bare_character(x = x)) { if (!all(nzchar(x = x))) { abort(message = "'x' cannot be empty") } # Handle cases where `x` is unnamed if (!any(have_name(x = x))) { # `x` is a vector with values in `names` # Return a list for every value in `x` that's present in `names` # with a value of `default` if (any(x %in% names)) { x <- intersect(x = x, y = names) ret <- vector(mode = 'list', length = length(x = x)) names(x = ret) <- x for (i in seq_along(along.with = ret)) { ret[[i]] <- default } return(ret) } # `x` is a vector of default values # Return a list for every value in `names` with a value of `x` ret <- vector(mode = 'list', length = length(x = names)) names(x = ret) <- names for (i in seq_along(along.with = ret)) { ret[[i]] <- unique(x = x) } return(ret) } # `x` is named # Turn `x` into a list and continue on x <- as.list(x = x) } # `x` is a list # Find entries of `x` that correspond to a value in `names` # Assign new value of `default` for (i in seq_along(along.with = x)) { if (is_scalar_character(x = x[[i]]) && x[[i]] %in% names) { names(x = x)[i] <- x[[i]] x[[i]] <- default } } # Identify values of `x` in `names` x.use <- intersect(x = names(x = x), y = names) if (!length(x = x.use) && is_named(x = x)) { abort(message = "None of the values of 'x' match with 'names") } #`Return only values of `x` that are in `names`` return(x[x.use]) } #' Get the Subobject Names #' #' @inheritParams .Collections #' @param collapse Collapse the list into a vector #' #' @return If \code{collapse = TRUE}, then a vector with the names of all #' subobjects; otherwise, a named list where the names are the names of the #' collections and the values are the names of subobjects within the collection #' #' @keywords internal #' #' @export #' #' @family subobjects #' @keywords utils #' #' @examples #' .Subobjects(pbmc_small) #' .Subobjects <- function( object, exclude = c('misc', 'tools'), collapse = TRUE, ... ) { subobjects <- sapply( X = .Collections(object = object, exclude = exclude, ...), FUN = function(x) { return(names(x = slot(object = object, name = x))) }, simplify = FALSE, USE.NAMES = TRUE ) if (isTRUE(x = collapse)) { subobjects <- unlist(x = subobjects, use.names = FALSE) } return(subobjects) } #' Attach Required Packages #' #' Helper function to attach required packages. Detects if a package is already #' attached and if so, skips it. Should be called in \code{\link[base]{.onAttach}} #' #' @param deps A character vector of packages to attach #' #' @template return-null #' #' @export #' #' @concept utils #' #' @template lifecycle-superseded #' @section Lifecycle: #' \code{AttachDeps} has been superseded as of \pkg{SeuratObject} v5.0.0; #' as an alternative, list dependencies in the \code{Depends} section of #' \code{DESCRIPTION} #' #' @examples #' # Use in your .onAttach hook #' if (FALSE) { #' .onAttach <- function(libname, pkgname) { #' AttachDeps(c("SeuratObject", "rlang")) #' } #' } #' AttachDeps <- function(deps) { for (d in deps) { if (!paste0('package:', d) %in% search()) { packageStartupMessage("Attaching ", d) attachNamespace(ns = d) } } return(invisible(x = NULL)) } #' Check the Use of Dots #' #' Function to check the use of unused arguments passed to \code{...}; this #' function is designed to be called from another function to see if an #' argument passed to \code{...} remains unused and alert the user if so. Also #' accepts a vector of function or function names to see if \code{...} can be #' used in a downstream function #' #' Behavior of \code{CheckDots} can be controlled by the following option(s): #' \describe{ #' \item{\dQuote{\code{Seurat.checkdots}}}{Control how to alert the presence #' of unused arguments in \code{...}; choose from #' \itemize{ #' \item \dQuote{\code{warn}}: emit a warning (default) #' \item \dQuote{\code{error}}: throw an error #' \item \dQuote{\code{silent}}: no not alert the presence of unused #' arguments in \code{...} #' } #' } #' } #' #' @param ... Arguments passed to a function that fall under \code{...} #' @param fxns A list/vector of functions or function names #' #' @return Emits either an error or warning if an argument passed is unused; #' invisibly returns \code{NULL} #' #' @importFrom utils isS3stdGeneric methods argsAnywhere isS3method #' #' @keywords internal #' #' @export #' #' @concept utils #' #' @examples #' \dontrun{ #' f <- function(x, ...) { #' CheckDots(...) #' return(x ^ 2) #' } #' f(x = 3, y = 9) #' } #' CheckDots <- function(..., fxns = NULL) { args.names <- names(x = list(...)) if (length(x = list(...)) == 0) { return(invisible(x = NULL)) } if (is.null(x = args.names)) { abort(message = "No named arguments passed") } if (length(x = fxns) == 1) { fxns <- list(fxns) } for (f in fxns) { if (!(is.character(x = f) || is.function(x = f))) { abort(message = paste( "CheckDots only works on characters or functions, not", class(x = f)[1L] )) } } fxn.args <- suppressWarnings(expr = sapply( X = fxns, FUN = function(x) { x <- tryCatch( expr = if (isS3stdGeneric(f = x)) { as.character(x = methods(generic.function = x)) } else { x }, error = function(...) { return(x) } ) x <- if (is.character(x = x)) { sapply(X = x, FUN = argsAnywhere, simplify = FALSE, USE.NAMES = TRUE) } else if (length(x = x) <= 1) { list(x) } return(sapply( X = x, FUN = function(f) { return(names(x = formals(fun = f))) }, simplify = FALSE, USE.NAMES = TRUE )) }, simplify = FALSE, USE.NAMES = TRUE )) fxn.args <- unlist(x = fxn.args, recursive = FALSE) fxn.null <- vapply( X = fxn.args, FUN = is.null, FUN.VALUE = logical(length = 1L) ) if (all(fxn.null) && !is.null(x = fxns)) { stop("None of the functions passed could be found", call. = FALSE) } else if (any(fxn.null)) { warning( "The following functions passed could not be found: ", paste(names(x = which(x = fxn.null)), collapse = ', '), call. = FALSE, immediate. = TRUE ) fxn.args <- Filter(f = Negate(f = is.null), x = fxn.args) } dfxns <- vector(mode = 'logical', length = length(x = fxn.args)) names(x = dfxns) <- names(x = fxn.args) for (i in 1:length(x = fxn.args)) { dfxns[i] <- any(grepl(pattern = '...', x = fxn.args[[i]], fixed = TRUE)) } if (any(dfxns)) { dfxns <- names(x = which(x = dfxns)) if (any(nchar(x = dfxns) > 0)) { fx <- vapply( X = Filter(f = nchar, x = dfxns), FUN = function(x) { if (isS3method(method = x)) { x <- unlist(x = strsplit(x = x, split = '\\.')) x <- x[length(x = x) - 1L] } return(x) }, FUN.VALUE = character(length = 1L) ) message( "The following functions and any applicable methods accept the dots: ", paste(unique(x = fx), collapse = ', ') ) if (any(nchar(x = dfxns) < 1)) { message( "In addition, there is/are ", length(x = Filter(f = Negate(f = nchar), x = dfxns)), " other function(s) that accept(s) the dots" ) } } else { message("There is/are ", length(x = dfxns), 'function(s) that accept(s) the dots') } } else { unused <- Filter( f = function(x) { return(!x %in% unlist(x = fxn.args)) }, x = args.names ) if (length(x = unused) > 0) { msg <- paste0( "The following arguments are not used: ", paste(unused, collapse = ', ') ) switch( EXPR = getOption(x = "Seurat.checkdots", default = 'warn'), "warn" = warning(msg, call. = FALSE, immediate. = TRUE), "stop" = stop(msg), "silent" = NULL, stop("Invalid Seurat.checkdots option. Please choose one of warn, stop, silent") ) # unused.hints <- sapply(X = unused, FUN = OldParamHints) # names(x = unused.hints) <- unused # unused.hints <- na.omit(object = unused.hints) # if (length(x = unused.hints) > 0) { # message( # "Suggested parameter: ", # paste(unused.hints, "instead of", names(x = unused.hints), collapse = '; '), # "\n" # ) # } } } return(invisible(x = NULL)) } #' Check features names format #' #' @param data a matrix input, rownames(data) are feature names #' #' @return \code{data} with update feature names #' #' @keywords internal #' #' @export #' CheckFeaturesNames <- function(data) { if (any(grepl(pattern = "_", x = rownames(x = data)))) { warning( "Feature names cannot have underscores ('_'), replacing with dashes ('-')", call. = FALSE, immediate. = TRUE ) rownames(x = data) <- gsub( pattern = "_", replacement = "-", x = rownames(x = data) ) } if (any(grepl(pattern = "|", x = rownames(x = data), fixed = TRUE))) { warning( "Feature names cannot have pipe characters ('|'), replacing with dashes ('-')", call. = FALSE, immediate. = TRUE ) rownames(x = data) <- gsub( pattern = "|", replacement = "-", x = rownames(x = data), fixed = TRUE ) } return(data) } #' Conditional Garbage Collection #' #' Call \code{gc} only when desired #' #' @param option ... #' #' @template return-null #' #' @export #' #' @concept utils #' CheckGC <- function(option = 'SeuratObject.memsafe') { if (isTRUE(x = getOption(x = option, default = FALSE))) { gc(verbose = FALSE) } return(invisible(x = NULL)) } #' Check layers names for the input list #' #' #' @param matrix.list A list of matrices #' @param layers.type layers type, such as counts or data #' #' #' @export #' #' @concept utils #' CheckLayersName <- function( matrix.list, layers.type = c('counts', 'data') ) { layers.type <- match.arg(arg = layers.type) if (is.null(x = matrix.list)) { return(matrix.list) } if (!inherits(x = matrix.list, what = 'list')) { matrix.list <- list(matrix.list) } if (length(x = matrix.list) == 1) { names(x = matrix.list) <- layers.type } else { endings <- seq_along(along.with = matrix.list) for (i in 1:length(x = matrix.list)) { name <- names(x = matrix.list)[i] if (!is.null(name) && nzchar(x = name)) { if (grepl(pattern = paste0('^', layers.type, '[._\\0-9-]+'), x = name)) { name <- gsub( pattern = paste0(layers.type, '[._\\0-9-]+'), replacement = "", x = name ) # If replacement leaves empty string if (!nzchar(x = name)) { name <- i } } endings[i] <- name } } names(x = matrix.list) <- paste0(paste0(layers.type, '.'), endings) names(x = matrix.list) <- make.unique(names = names(x = matrix.list), sep = '') } return(matrix.list) } #' Generate a Class Key #' #' Generate class keys for S4 classes. A class key follows the following #' structure: \dQuote{\code{package:class}} #' #' @param class Class name #' @param package Optional name of package; by default, will search namespaces #' of loaded packages to determine the providing package #' #' @return The class key (\dQuote{\code{package:class}}) #' #' @importFrom methods getClass slot #' #' @keywords internal #' #' @export #' #' @concept utils #' @family s4list #' #' @examples #' ClassKey("Seurat") #' ClassKey <- function(class, package = NULL) { class <- class[1L] package <- package %||% slot( object = getClass(Class = class), name = 'package' ) return(paste(package, class, sep = ':')) } #' Find the default \code{\link{DimReduc}} #' #' Searches for \code{\link{DimReduc}s} matching \dQuote{umap}, \dQuote{tsne}, #' or \dQuote{pca}, case-insensitive, and in that order. Priority given to #' \code{\link{DimReduc}s} matching the \code{DefaultAssay} or assay specified #' (eg. \dQuote{pca} for the default assay weights higher than \dQuote{umap} #' for a non-default assay) #' #' @param object A \code{\link{Seurat}} object #' @param assay Name of assay to use; defaults to the default assay of the object #' #' @return The default \code{\link{DimReduc}}, if possible #' #' @export #' #' @concept utils #' #' @examples #' DefaultDimReduc(pbmc_small) #' DefaultDimReduc <- function(object, assay = NULL) { object <- UpdateSlots(object = object) assay <- assay %||% DefaultAssay(object = object) drs.use <- c('umap', 'tsne', 'pca') dim.reducs <- .FilterObjects(object = object, classes.keep = 'DimReduc') drs.assay <- Filter( f = function(x) { return(DefaultAssay(object = object[[x]]) == assay) }, x = dim.reducs ) if (length(x = drs.assay)) { index <- lapply( X = drs.use, FUN = grep, x = drs.assay, ignore.case = TRUE ) index <- Filter(f = length, x = index) if (length(x = index)) { return(drs.assay[min(index[[1]])]) } } index <- lapply( X = drs.use, FUN = grep, x = dim.reducs, ignore.case = TRUE ) index <- Filter(f = length, x = index) if (!length(x = index)) { abort(message = paste0( "Unable to find a DimReduc matching one of ", .Oxford(drs.use), "; please specify a dimensional reduction to use" )) } return(dim.reducs[min(index[[1]])]) } #' Radian/Degree Conversions #' #' Convert degrees to radians and vice versa #' #' @param rad Angle in radians #' #' @return \code{Degrees}: \code{rad} in degrees #' #' @name Angles #' @rdname angles #' #' @keywords internal #' #' @export #' #' @concept utils #' @family angles #' #' @examples #' Degrees(pi) #' Degrees <- function(rad) { return(rad * (180 / pi)) } #' Empty Data Frames #' #' Create an empty \link[base:data.frame]{data frame} with no row names and #' zero columns #' #' @param n Number of rows for the data frame #' #' @return A \link[base:data.frame]{data frame} with \code{n} rows and #' zero columns #' #' @keywords internal #' #' @export #' #' @concept utils #' #' @examples #' EmptyDF(4L) #' EmptyDF <- function(n) { return(as.data.frame(x = matrix(nrow = n, ncol = 0L))) } #' Extract delimiter information from a string. #' #' Parses a string (usually a cell name) and extracts fields based #' on a delimiter #' #' @param string String to parse. #' @param field Integer(s) indicating which field(s) to extract. Can be a #' vector multiple numbers. #' @param delim Delimiter to use, set to underscore by default. #' #' @return A new string, that parses out the requested fields, and #' (if multiple), rejoins them with the same delimiter #' #' @keywords internal #' #' @export #' #' @concept utils #' #' @examples #' ExtractField('Hello World', field = 1, delim = '_') #' ExtractField <- function(string, field = 1, delim = "_") { fields <- as.numeric(x = unlist(x = strsplit( x = as.character(x = field), split = "," ))) if (length(x = fields) == 1) { return(strsplit(x = string, split = delim)[[1]][field]) } return(paste( strsplit(x = string, split = delim)[[1]][fields], collapse = delim )) } #' Check List Names #' #' Check to see if a list has names; also check to enforce that all names are #' present and unique #' #' @param x A list #' @param all.unique Require that all names are unique from one another #' @param allow.empty Allow empty (\code{nchar = 0}) names #' @param pass.zero Pass on zero-length lists #' #' @return \code{TRUE} if ..., otherwise \code{FALSE} #' #' @importFrom rlang is_bare_list #' #' @export #' #' @concept utils #' #' @examples #' IsNamedList(list()) #' IsNamedList(list(), pass.zero = TRUE) #' IsNamedList(list(1, 2, 3)) #' IsNamedList(list(a = 1, b = 2, c = 3)) #' IsNamedList(list(a = 1, 2, c = 3)) #' IsNamedList(list(a = 1, 2, c = 3), allow.empty = TRUE) #' IsNamedList(list(a = 1, a = 2, a = 3)) #' IsNamedList(list(a = 1, a = 2, a = 3), all.unique = FALSE) #' IsNamedList <- function( x, all.unique = TRUE, allow.empty = FALSE, pass.zero = FALSE ) { if (!is_bare_list(x = x)) { return(FALSE) } if (isTRUE(x = pass.zero) && !length(x = x)) { return(TRUE) } n <- names(x = x) named <- !is.null(x = n) if (!isTRUE(x = allow.empty)) { named <- named && all(vapply( X = n, FUN = nchar, FUN.VALUE = integer(length = 1L) )) } if (isTRUE(x = all.unique)) { named <- named && (length(x = n) == length(x = unique(x = n))) } return(named) } #' @name s4list #' @rdname s4list #' #' @return \code{IsS4List}: \code{TRUE} if \code{x} is a list with an S4 class #' definition attribute #' #' @export #' #' @examples #' IsS4List(pbmc.list) #' IsS4List <- function(x) { return( is_bare_list(x = x) && isTRUE(x = grepl( pattern = '^[[:alnum:]]+:[[:alnum:]]+$', x = attr(x = x, which = 'classDef') )) ) } #' @name s4list #' @rdname s4list #' #' @return \code{ListToS4}: An S4 object as defined by the S4 class definition #' attribute #' #' @importFrom methods getClassDef new #' #' @export #' #' @examples #' pbmc2 <- ListToS4(pbmc.list) #' pbmc2 #' class(pbmc2) #' Reductions(pbmc2) #' validObject(pbmc2) #' ListToS4 <- function(x) { if (!is_bare_list(x = x)) { return(x) } for (i in seq_along(along.with = x)) { if (!is.null(x = x[[i]])) { x[[i]] <- ListToS4(x = x[[i]]) } } classdef <- attr(x = x, which = 'classDef') x <- Filter(f = Negate(f = is.function), x = x) attr(x = x, which = 'classDef') <- classdef if (!IsS4List(x = x)) { return(x) } classdef <- unlist(x = strsplit( x = attr(x = x, which = 'classDef'), split = ':' )) pkg <- classdef[1L] cls <- classdef[2L] formal <- getClassDef(Class = cls, package = pkg, inherits = FALSE) return(do.call(what = new, args = c(list(Class = formal), x))) } #' Check the existence of a package #' #' @param ... Package names #' @param error If true, throw an error if the package doesn't exist #' #' @return Invisibly returns boolean denoting if the package is installed #' #' @export #' #' @concept utils #' #' @section Lifecycle: #' #' \Sexpr[stage=build,results=rd]{lifecycle::badge("deprecated")} #' #' \code{PackageCheck} was deprecated in version 5.0.0; please use #' \code{\link[rlang:check_installed]{rlang::check_installed}()} instead #' #' @examples #' PackageCheck("SeuratObject", error = FALSE) #' PackageCheck <- function(..., error = TRUE) { .Deprecate( when = '5.0.0', what = 'PackageCheck()', with = 'rlang::check_installed()' ) pkgs <- unlist(x = c(...), use.names = FALSE) package.installed <- vapply( X = pkgs, FUN = requireNamespace, FUN.VALUE = logical(length = 1L), quietly = TRUE ) if (error && any(!package.installed)) { stop( "Cannot find the following packages: ", paste(pkgs[!package.installed], collapse = ', '), ". Please install" ) } invisible(x = package.installed) } #' Polygon Vertices #' #' Calculate the vertices of a regular polygon given the number of sides and #' its radius (distance from center to vertex). Also permits transforming the #' resulting coordinates by moving the origin and altering the initial angle #' #' @param n Number of sides of the polygon #' @param r Radius of the polygon #' @param xc,yc X/Y coordinates for the center of the polygon #' @param t1 Angle of the first vertex in degrees #' #' @return A \code{\link[base]{data.frame}} with \code{n} rows and two columns: #' \describe{ #' \item{\code{x}}{X positions of each coordinate} #' \item{\code{y}}{Y positions of each coordinate} #' } #' #' @keywords internal #' #' @export #' #' @concept utils #' @family angles #' #' @references \url{https://stackoverflow.com/questions/3436453/calculate-coordinates-of-a-regular-polygons-vertices} #' #' @examples #' coords <- PolyVtx(5, t1 = 90) #' coords #' if (requireNamespace("ggplot2", quietly = TRUE)) { #' ggplot2::ggplot(coords, ggplot2::aes(x = x, y = y)) + ggplot2::geom_polygon() #' } #' PolyVtx <- function(n, r = 1L, xc = 0L, yc = 0L, t1 = 0) { if (!is_bare_integerish(x = n, n = 1L, finite = TRUE)) { abort(message = "'n' must be a single integer") } else if (n < 3L) { abort(message = "'n' must be greater than or equal to 3") } stopifnot(is_bare_integerish(x = r, n = 1L, finite = TRUE)) stopifnot(is_bare_integerish(x = xc, n = 1L, finite = TRUE)) stopifnot(is_bare_integerish(x = yc, n = 1L, finite = TRUE)) stopifnot(is_bare_numeric(x = t1, n = 1L)) t1 <- Radians(deg = t1) coords <- matrix(data = 0, nrow = n, ncol = 2) colnames(x = coords) <- c('x', 'y') for (i in seq_len(length.out = n)) { theta <- 2 * pi * (i - 1) / n + t1 coords[i, ] <- c( xc + r * cos(x = theta), yc + r * sin(x = theta) ) } return(as.data.frame(x = coords)) } #' @param deg Angle in degrees #' #' @return \code{Radians}: \code{deg} in radians #' #' @rdname angles #' #' @keywords internal #' #' @export #' #' @examples #' Radians(180) #' Radians <- function(deg) { return(deg * (pi / 180)) } #' Generate a random name #' #' Make a name from randomly sampled characters, pasted together with no spaces #' #' @param length How long should the name be #' @param chars A vector of 1-length characters to use to generate the name #' @param ... Extra parameters passed to \code{\link[base]{sample}} #' #' @return A character with \code{nchar == length} of randomly sampled letters #' #' @seealso \code{\link[base]{sample}} #' #' @export #' #' @concept utils #' #' @examples #' set.seed(42L) #' RandomName() #' RandomName(7L, replace = TRUE) #' RandomName <- function(length = 5L, chars = letters, ...) { CheckDots(..., fxns = 'sample') chars <- unique(x = unlist(x = strsplit( x = as.character(x = chars), split = '' ))) return(paste(sample(x = chars, size = length, ...), collapse = '')) } #' Merge Sparse Matrices by Row #' #' Merge two or more sparse matrices by rowname. #' #' @details #' Shared matrix rows (with the same row name) will be merged, and unshared #' rows (with different names) will be filled with zeros in the matrix not #' containing the row. #' #' @param mat1 First matrix #' @param mat2 Second matrix or list of matrices #' #' @return Returns a sparse matrix #' #' @importFrom methods as # #' @export #' #' @concept utils #' RowMergeSparseMatrices <- function(mat1, mat2) { all.mat <- c(list(mat1), mat2) all.colnames <- all.rownames <- vector( mode = 'list', length = length(x = all.mat) ) for (i in seq_along(along.with = all.mat)) { if (is.data.frame(x = all.mat[[1]])) { all.mat[[i]] <- as.matrix(x = all.mat[[i]]) } all.rownames[[i]] <- rownames(x = all.mat[[i]]) all.colnames[[i]] <- colnames(x = all.mat[[i]]) } use.cbind <- all(duplicated(x = all.rownames)[2:length(x = all.rownames)]) if (isTRUE(x = use.cbind)) { new.mat <- do.call(what = cbind, args = all.mat) } else { all.mat <- lapply(X = all.mat, FUN = as, Class = "RsparseMatrix") all.names <- unique(x = unlist(x = all.rownames)) new.mat <- RowMergeMatricesList( mat_list = all.mat, mat_rownames = all.rownames, all_rownames = all.names ) rownames(x = new.mat) <- make.unique(names = all.names) } colnames(x = new.mat) <- make.unique(names = unlist(x = all.colnames)) return(new.mat) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for Seurat-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' @rdname dot-AssayClass #' @method .AssayClass default #' @export #' .AssayClass.default <- function(object) { return(class(x = object)[1L]) } #' @importFrom methods getClass #' #' @rdname dot-ClassPkg #' #' @method .ClassPkg default #' @export #' .ClassPkg.default <- function(object) { if (!isS4(object)) { return(NA_character_) } return(slot(object = getClass(Class = class(x = object)), name = 'package')) } #' @rdname dot-ClassPkg #' @method .ClassPkg DelayedArray #' @export #' .ClassPkg.DelayedArray <- function(object) { check_installed( pkg = 'DelayedArray', reason = 'for working with delayed arrays' ) return(.ClassPkg(object = DelayedArray::seed(x = object))) } #' @rdname dot-ClassPkg #' @method .ClassPkg R6 #' @export #' .ClassPkg.R6 <- function(object) { for (cls in class(x = object)) { x <- eval(expr = as.symbol(x = cls)) if (inherits(x = x, what = 'R6ClassGenerator')) { return(.ClassPkg(object = x)) } } warn(message = "No r6") return('R6') } #' @rdname dot-ClassPkg #' @method .ClassPkg R6ClassGenerator #' @export #' .ClassPkg.R6ClassGenerator <- function(object) { return(environmentName(env = object$parent_env)) } #' @rdname dot-DiskLoad #' @method .DiskLoad default #' @export #' .DiskLoad.default <- function(x) { return(NULL) } #' @rdname dot-DiskLoad #' @method .DiskLoad 10xMatrixH5 #' @export #' .DiskLoad.10xMatrixH5 <- function(x) { abort(message = "Unable to determine the feature type of 10x-based BPCells matrices") check_installed( pkg = 'BPCells', reason = 'for working with BPCells matrices' ) f <- paste( 'function(x)', 'BPCells::open_matrix_10x_hdf5(path = x, feature_type =', sQuote(x = '', q = FALSE), ')' ) return(f) } #' @rdname dot-DiskLoad #' @method .DiskLoad AnnDataMatrixH5 #' @export #' .DiskLoad.AnnDataMatrixH5 <- function(x) { check_installed( pkg = 'BPCells', reason = 'for working with BPCells matrices' ) f <- paste( 'function(x)', 'BPCells::open_matrix_anndata_hdf5(path = x, group =', sQuote(x = slot(object = x, name = 'group'), q = FALSE), ')' ) return(f) } #' @rdname dot-DiskLoad #' @method .DiskLoad DelayedMatrix #' @export #' .DiskLoad.DelayedMatrix <- function(x) { check_installed( pkg = 'DelayedArray', reason = 'for working with delayed matrices' ) seed <- DelayedArray::seed(x = x) return(.DiskLoad(x = DelayedArray::DelayedArray(seed = seed))) } #' @rdname dot-DiskLoad #' @method .DiskLoad H5ADMatrix #' @export #' .DiskLoad.H5ADMatrix <- function(x) { check_installed( pkg = 'HDF5Array', reason = 'for working with H5AD matrices' ) sparse <- DelayedArray::is_sparse(x = x) layer <- if (isTRUE(x = sparse)) { slot(object = DelayedArray::seed(x = x), name = 'group') } else { slot(object = DelayedArray::seed(x = x), name = 'name') } layer <- if (layer == '/X') { NULL } else { basename(path = layer) } f <- paste( "function(x)", "HDF5Array::H5ADMatrix(filepath = x", if (!is.null(x = layer)) { paste(", layer =", sQuote(x = layer, q = FALSE)) }, ")" ) return(f) } #' @rdname dot-DiskLoad #' @method .DiskLoad HDF5Matrix #' @export #' .DiskLoad.HDF5Matrix <- function(x) { check_installed( pkg = 'HDF5Array', reason = 'for working with HDF5 matrices' ) sparse <- DelayedArray::is_sparse(x = x) name <- slot(object = DelayedArray::seed(x = x), name = 'name') f <- paste( "function(x)", "HDF5Array::HDF5Array(filepath = x, name =", sQuote(x = name, q = FALSE), ", as.sparse =", sparse, ")" ) return(f) } #' @rdname dot-DiskLoad #' @method .DiskLoad IterableMatrix #' @export #' .DiskLoad.IterableMatrix <- function(x) { check_installed( pkg = 'BPCells', reason = 'for working with BPCells matrices' ) fxns <- lapply( X = BPCells::all_matrix_inputs(x = x), FUN = .DiskLoad ) fxns <- Filter(f = Negate(f = is.null), x = fxns) if (!length(x = fxns)) { return(NULL) } fn <- if (length(x = fxns) > 1L) { # fxns <- paste('list(', paste(sQuote(x = fxns, q = FALSE), collapse = ', '), ')') fn <- paste( "function(x) {", "paths <- unlist(x = strsplit(x = x, split = ','));", "fxns <- list(", paste(sQuote(x = fxns, q = FALSE), collapse = ', '), ");", "mats <- vector(mode = 'list', length = length(x = paths));", "for (i in seq_along(paths)) {", "fn <- eval(str2lang(fxns[[i]]));", "mats[[i]] <- fn(paths[i]);", "};", "return(Reduce(cbind, mats));", "}" ) fn # abort(message = "too many matrices") } else { fxns[[1L]] } return(fn) } #' @rdname dot-DiskLoad #' @method .DiskLoad MatrixDir #' @export #' .DiskLoad.MatrixDir <- function(x) { check_installed( pkg = 'BPCells', reason = 'for working with BPCells matrices' ) f <- paste( 'function(x)', 'BPCells::open_matrix_dir(dir = x)' ) return(f) } #' @rdname dot-DiskLoad #' @method .DiskLoad MatrixH5 #' @export #' .DiskLoad.MatrixH5 <- function(x) { check_installed( pkg = 'BPCells', reason = 'for working with BPCells matrices' ) f <- paste( 'function(x)', 'BPCells::open_matrix_hdf5(path = x, group =', sQuote(x = slot(object = x, name = 'group'), q = FALSE), ')' ) return(f) } #' @rdname dot-DiskLoad #' @method .DiskLoad TileDBMatrix #' @export #' .DiskLoad.TileDBMatrix <- function(x) { check_installed( pkg = 'TileDBArray', reason = 'for working with TileDB matrices' ) tdb.attr <- slot(object = DelayedArray::seed(x = x), name = 'attr') f <- paste( 'function(x)', 'TileDBArray::TileDBArray(x = x, attr =', sQuote(x = tdb.attr, q = FALSE), ')' ) return(f) } #' @rdname dot-FilePath #' @method .FilePath default #' @export #' .FilePath.default <- function(x) { return(NULL) } #' @rdname dot-FilePath #' @method .FilePath DelayedMatrix #' @export #' .FilePath.DelayedMatrix <- function(x) { check_installed( pkg = 'DelayedArray', reason = 'for working with delayed matrices' ) path <- tryCatch( expr = normalizePath(path = DelayedArray::path(object = x)), error = \(...) NULL ) if (is.null(x = path)) { warn(message = "The matrix provided does not exist on-disk") } return(path) } #' @rdname dot-FilePath #' @method .FilePath IterableMatrix #' @export #' .FilePath.IterableMatrix <- function(x) { check_installed(pkg = "BPCells", reason = "for working with BPCells matrices") matrices <- BPCells::all_matrix_inputs(x = x) paths <- vector(mode = 'character', length = length(x = matrices)) for (i in seq_along(along.with = matrices)) { mode <- .BPMatrixMode(object = matrices[[i]]) paths[i] <- switch( EXPR = mode, memory = '', file = slot(object = matrices[[i]], name = "path"), directory = slot(object = matrices[[i]], name = 'dir'), abort(message = paste("Unknown BPCells matrix mode:", sQuote(x = mode))) ) } if (length(paths) > 1){ paths <- paste(paths, collapse = ",") } return(paths) } #' @rdname dot-SelectFeatures #' @method .SelectFeatures list #' @export #' .SelectFeatures.list <- function( object, all.features = NULL, nfeatures = Inf, ... ) { if (length(x = object) == 1L) { return(head(x = object[[1L]], n = nfeatures)) } features <- unlist(x = object, use.names = FALSE) features <- sort(x = table(features), decreasing = TRUE) # Select only features present in all entries if (!is.null(x = all.features)) { present <- intersect(x = names(x = features), y = all.features) if (!length(x = present)) { abort( message = "None of the features provided are present in the feature set" ) } features <- features[present] } tie.val <- features[min(nfeatures, length(x = features))] # Select features selected <- names(x = features[which(x = features > tie.val)]) if (length(x = features)) { selected <- .FeatureRank(features = selected, flist = object) } tied <- .FeatureRank( features = names(x = features[which(x = features == tie.val)]), flist = object ) return(head(x = c(selected, tied), n = nfeatures)) } #' @rdname as.Centroids #' @method as.Centroids Segmentation #' @export #' as.Centroids.Segmentation <- function( x, nsides = NULL, radius = NULL, theta = NULL, ... ) { coords <- as(object = x, Class = 'Centroids') if (!is.null(x = nsides)) { slot(object = coords, name = 'nsides') <- nsides } if (!is.null(x = theta)) { slot(object = coords, name = 'theta') <- theta } if (is.null(x = radius)) { radius <- vapply( X = Cells(x = x), FUN = function(i) { area <- slot( object = slot(object = x, name = 'polygons')[[i]], name = 'area' ) return(sqrt(x = area / pi)) }, FUN.VALUE = numeric(length = 1L), USE.NAMES = FALSE ) } slot(object = coords, name = 'radius') <- radius validObject(object = coords) return(coords) # x <- c() # y <- c() # radius <- c() # nsides <- 0 # for (cell in Cells(x)) { # a <- x@polygons[[cell]]@area # radius <- c(radius, sqrt(a / pi)) # x <- c(x, x@polygons[[cell]]@labpt[1]) # y <- c(y, x@polygons[[cell]]@labpt[2]) # } # coords <- data.frame(x, y) # rownames(x = coords) = Cells(x) # return( # CreateCentroids( # coords, # radius = radius, # theta = rep(0, length(radius)), # nsides = rep(0, length(radius)) # ) # ) } #' @rdname as.Centroids #' @method as.Segmentation Centroids #' @export #' as.Segmentation.Centroids <- function(x, ...) { return(as(object = x, Class = 'Segmentation')) } #' @param row.names \code{NULL} or a character vector giving the row names for #' the data; missing values are not allowed #' #' @rdname as.sparse #' @export #' @method as.sparse data.frame #' as.sparse.data.frame <- function(x, row.names = NULL, ...) { CheckDots(...) dnames <- list(row.names %||% rownames(x = x), colnames(x = x)) if (length(x = dnames[[1]]) != nrow(x = x)) { stop("Differing numbers of rownames and rows", call. = FALSE) } x <- as.data.frame(x = x) dimnames(x = x) <- dnames return(as.sparse(x = as.matrix(x = x))) } #' @importFrom methods as #' #' @rdname as.sparse #' @export #' @method as.sparse Matrix #' as.sparse.Matrix <- function(x, ...) { CheckDots(...) return(as(object = as(object = as(object = x, Class = "dMatrix"), Class = "generalMatrix"), Class = "CsparseMatrix")) } #' @rdname as.sparse #' @export #' @method as.sparse matrix #' as.sparse.matrix <- function(x, ...) { if (is.character(x = x)) { dnames <- dimnames(x = x) nc <- ncol(x = x) x <- matrix(data = as.numeric(x = x), ncol = nc) dimnames(x = x) <- dnames } x <- as(object = x, Class = "Matrix") return(as.sparse.Matrix(x, ...)) } #' @rdname as.sparse #' @export #' @method as.sparse ngCMatrix #' as.sparse.ngCMatrix <- function(x, ...) { return(as(object = x, Class = "dMatrix")) } #' @rdname CheckMatrix #' @method CheckMatrix default #' @export #' CheckMatrix.default <- function(object, checks, ...) { return(invisible(x = NULL)) } #' @rdname CheckMatrix #' @method CheckMatrix dMatrix #' @export #' CheckMatrix.dMatrix <- function( object, checks = c('infinite', 'logical', 'integer', 'na'), ... ) { checks <- arg_match(arg = checks, multiple = TRUE) x <- slot(object = object, name = 'x') for (i in checks) { switch( EXPR = i, 'infinite' = if (any(is.infinite(x = x))) { warn(message = "Input matrix contains infinite values") }, 'logical' = if (any(is.logical(x = x))) { warn(message = "Input matrix contains logical values") }, 'integer' = if (!all(round(x = x) == x, na.rm = TRUE)) { warn(message = "Input matrix contains non-integer values") }, 'na' = if (anyNA(x = x)) { warn(message = "Input matrix contains NA/NaN values") }, ) } return(invisible(x = NULL)) } #' @rdname CheckMatrix #' @method CheckMatrix lMatrix #' @export #' CheckMatrix.lMatrix <- function( object, checks = c('infinite', 'logical', 'integer', 'na'), ... ) { warn(message = "Input matrix contains logical values") return(invisible(x = NULL)) } #' @rdname IsMatrixEmpty #' @export #' @method IsMatrixEmpty default #' IsMatrixEmpty.default <- function(x) { matrix.dims <- dim(x = x) if (is.null(x = matrix.dims)) { return(FALSE) } matrix.na <- all(matrix.dims == 1) && all(is.na(x = x)) return(all(matrix.dims == 0) || matrix.na) } #' @importFrom methods slotNames #' #' @rdname s4list #' @export #' @method S4ToList default #' S4ToList.default <- function(object) { obj.list <- sapply( X = slotNames(x = object), FUN = function(x) { return(S4ToList(object = slot(object = object, name = x))) }, simplify = FALSE, USE.NAMES = TRUE ) attr(x = obj.list, which = 'classDef') <- paste( c( attr(x = class(x = object), which = 'package'), class(x = object) ), collapse = ':' ) return(obj.list) } #' @rdname s4list #' @export #' @method S4ToList list #' S4ToList.list <- function(object) { if (length(x = object)) { for (i in seq_along(along.with = object)) { if (!is.null(x = object[[i]])) { object[[i]] <- S4ToList(object = object[[i]]) } } } return(object) } #' Simplify segmentations by reducing the number of vertices #' #' @param coords A `Segmentation` object #' @param tol Numerical tolerance value to be used by the Douglas-Peuker algorithm #' @param topologyPreserve Logical determining if the algorithm should attempt to preserve the topology of the original geometry #' #' @return A `Segmentation` object with simplified segmentation vertices #' #' @rdname Simplify #' @method Simplify Spatial #' @export #' Simplify.Spatial <- function(coords, tol, topologyPreserve = TRUE) { check_installed(pkg = 'sf', reason = 'to simplify spatial data') class.orig <- class(x = coords) coords.orig <- coords dest <- ifelse( test = grepl(pattern = "^Spatial", x = class.orig), yes = class.orig, no = grep(pattern = "^Spatial", x = .Contains(object = coords), value = TRUE)[1L] ) x <- sf::st_as_sfc(as(object = coords, Class = dest)) coords <- sf::st_simplify( x = x, dTolerance = as.numeric(x = tol), preserveTopology = isTRUE(x = topologyPreserve)) coords <- sf::st_sf(geometry = coords) coords <- as(coords, Class = "Spatial") coords <- as(coords, Class = "Segmentation") slot(object = coords, name = "polygons") <- mapply( FUN = function(x, y) { slot(object = x, name = "ID") <- y return(x) }, slot(object = coords, name = "polygons"), Cells(coords.orig)) return(coords) } #' Generate empty dgC sparse matrix #' #' @param ncol,nrow Number of columns and rows in matrix #' @param rownames,colnames Optional row- and column names for the matrix #' #' @keywords internal #' #' @export #' SparseEmptyMatrix <- function(nrow, ncol, rownames = NULL, colnames = NULL) { return(new( Class = 'dgCMatrix', p = integer(length = ncol + 1L), Dim = c(as.integer(x = nrow), as.integer(x = ncol)), Dimnames = list(rownames, colnames) )) } #' @method StitchMatrix default #' @export #' StitchMatrix.default <- function(x, y, rowmap, colmap, ...) { abort(message = paste( "Stitching matrices of class", dQuote(x = class(x = x)[1L]), "is not yet supported" )) } #' @method StitchMatrix dgCMatrix #' @export #' StitchMatrix.dgCMatrix <- function(x, y, rowmap, colmap, ...) { on.exit(expr = CheckGC()) if (!is_bare_list(x = y)) { y <- list(y) } rowmap <- droplevels(x = rowmap) colmap <- droplevels(x = colmap) stopifnot(ncol(rowmap) == length(y) + 1L) stopifnot(ncol(colmap) == length(y) + 1L) stopifnot(identical(x = colnames(x = rowmap), y = colnames(x = colmap))) dimnames(x = x) <- list(rowmap[[1L]], colmap[[1L]]) for (i in seq_along(along.with = y)) { j <- i + 1L y[[i]] <- as(object = y[[i]], Class = 'dgCMatrix') dimnames(x = y[[i]]) <- list(rowmap[[j]], colmap[[j]]) } return(RowMergeSparseMatrices(mat1 = x, mat2 = y)) } #' @method StitchMatrix IterableMatrix #' @export #' StitchMatrix.IterableMatrix <- function(x, y, rowmap, colmap, ...) { on.exit(expr = CheckGC()) if (!is_bare_list(x = y)) { y <- list(y) } rowmap <- droplevels(x = rowmap) colmap <- droplevels(x = colmap) stopifnot(ncol(rowmap) == length(y) + 1L) stopifnot(ncol(colmap) == length(y) + 1L) stopifnot(identical(x = colnames(x = rowmap), y = colnames(x = colmap))) y <- c(x, y) for (i in seq_along(along.with = y)) { #expand matrix to the same size missing_row <- setdiff(x = rownames(x = rowmap), y = rowmap[[i]]) if (length(x = missing_row) > 0) { zero_i <- SparseEmptyMatrix( nrow = length(x = missing_row), ncol = ncol(x = y[[i]]), colnames = colmap[[i]], rownames = missing_row ) zero_i <- as(object = zero_i, Class = 'IterableMatrix') y[[i]] <- rbind(y[[i]], zero_i)[rownames(rowmap),] } } m <- Reduce(f = cbind, x = y) return(m) } #' @method StitchMatrix matrix #' @export #' StitchMatrix.matrix <- function(x, y, rowmap, colmap, ...) { on.exit(expr = CheckGC()) if (!is_bare_list(x = y)) { y <- list(y) } rowmap <- droplevels(x = rowmap) colmap <- droplevels(x = colmap) stopifnot(ncol(rowmap) == length(y) + 1L) stopifnot(ncol(colmap) == length(y) + 1L) stopifnot(identical(x = colnames(x = rowmap), y = colnames(x = colmap))) m <- matrix( data = 0, nrow = nrow(x = rowmap), ncol = nrow(x = colmap), dimnames = list(rownames(x = rowmap), rownames(x = colmap)) ) m[rowmap[[1L]], colmap[[1L]]] <- x for (i in seq_along(along.with = y)) { j <- i + 1L m[rowmap[[j]], colmap[[j]]] <- as.matrix(x = y[[i]]) } return(m) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for R-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # S4 methods #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Internal #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% .CheckNames <- function(x, n) { stopifnot(length(x = x) == length(x = n)) if (is.null(x = names(x = x))) { names(x = x) <- n } if (any(!nzchar(x = names(x = x)))) { idx <- which(x = !nzchar(x = names(x = x))) n2 <- setdiff(x = n, y = names(x = x)) if (length(x = idx) != length(x = n2)) { stop("Not all provided names fit with the values provided", call. = FALSE) } names(x = x)[idx] <- n2 } return(x) } #' @importFrom stats median #' .FeatureRank <- function(features, flist, ranks = FALSE) { franks <- vapply( X = features, FUN = function(x) { return(median(x = unlist(x = lapply( X = flist, FUN = function(fl) { if (x %in% fl) { return(which(x = x == fl)) } return(NULL) } )))) }, FUN.VALUE = numeric(length = 1L) ) franks <- sort(x = franks) if (!isTRUE(x = ranks)) { franks <- names(x = franks) } return(franks) } #' Move Files and Directories #' #' Move files and directories with \pkg{fs}; includes a handler for when #' \code{path} is a directory on a different filesystem than \code{new_path} #' by explicitly copying and deleting \code{path} #' #' @inherit fs::file_move params return #' @inheritParams rlang::caller_env #' #' @keywords internal #' #' @export #' #' @templateVar pkg fs #' @template note-reqdpkg #' #' @seealso \code{\link[fs:file_move]{fs::file_move}()} #' .FileMove <- function(path, new_path, overwrite = FALSE, n = 1L) { check_installed(pkg = "fs", reason = "for moving on-disk files") stopifnot( is_scalar_character(x = path), is_scalar_character(x = new_path), rlang::is_bare_logical(x = overwrite, n = 1L), is_bare_integerish(x = n, n = 1L, finite = TRUE) && n > 0 ) eexist <- function(err) { warn( message = paste( strwrap(x = paste( "Trying to move", sQuote(x = path), "to itself, skipping" )), collapse = '\n' ), class = c('WEXIST', 'EEXIST') ) return(fs::as_fs_path(x = path)) } hndlr <- function(err) { abort( message = err$message, class = class(x = err), call = caller_env(n = 4L + n) ) } if (fs::is_dir(path = path)) { path <- fs::path_expand(path = path) new_path <- fs::path_expand(path = new_path) new_path <- fs::dir_create(path = new_path) dest <- tryCatch( expr = fs::dir_copy( path = path, new_path = new_path, overwrite = overwrite ), EEXIST = eexist, error = hndlr ) } else if (fs::is_file(path = path)) { dest <- tryCatch( expr = fs::file_copy( path = path, new_path = new_path, overwrite = overwrite ), EEXIST = eexist, error = hndlr ) } else { abort( message = paste( strwrap(x = paste0( "Can't find path: ", sQuote(x = path), "; if path is relative, change working directory" )), sep = '\n' ), call = caller_env(n = 1L + n) ) } return(invisible(x = dest)) } #' @param pkg Name of package #' @param external Include packages imported, but not defined, by \code{pkg} #' @param old Includes S3 classes registered by #' \code{\link[methods]{setOldClass}} #' @param unions Include class unions #' #' @importFrom methods getClass getClasses isClassUnion isXS3Class #' #' @noRd #' .PkgClasses <- function( pkg = 'SeuratObject', external = FALSE, old = FALSE, unions = FALSE, virtual = NA, collapse = TRUE, include = NULL, exclude = NULL ) { classes <- getClasses(where = getNamespace(name = pkg)) include <- intersect(x = include, y = classes) # Filter out classes imported, but not defined by pkg if (!isTRUE(x = external)) { classes <- Filter( f = function(x) { return(slot(object = getClass(Class = x), name = 'package') == pkg) }, x = classes ) } # Filter out S3 classes if (!isTRUE(x = old)) { classes <- Filter( f = function(x) { return(!isXS3Class(classDef = getClass(Class = x))) }, x = classes ) } # Filter out class unions if (!isTRUE(x = unions)) { classes <- Filter(f = Negate(f = isClassUnion), x = classes) } # TODO: Remove virtual classes if (isFALSE(x = virtual)) { '' } # TODO: Collapse classes if (isTRUE(x = collapse)) { '' } # Add classes back classes <- union(x = classes, y = include) # Remove excluded classes classes <- setdiff(x = classes, y = exclude) return(classes) } #' Get English Vowels #' #' @return A vector with English vowels in lower case #' #' @keywords internal #' #' @examples #' .Vowels() #' #' @noRd #' .Vowels <- function() { return(c('a', 'e', 'i', 'o', 'u')) } #' Check a list of objects for duplicate cell names #' #' @param object.list List of Seurat objects #' @param verbose Print message about renaming #' @param stop Error out if any duplicate names exist #' #' @return Returns list of objects with duplicate cells renamed to be unique #' #' @keywords internal #' #' @noRd #' CheckDuplicateCellNames <- function(object.list, verbose = TRUE, stop = FALSE) { cell.names <- unlist(x = lapply(X = object.list, FUN = colnames)) if (anyDuplicated(x = cell.names)) { if (isTRUE(x = stop)) { stop("Duplicate cell names present across objects provided.", call. = FALSE) } if (verbose) { warning( "Some cell names are duplicated across objects provided. Renaming to enforce unique cell names.", call. = FALSE, immediate. = TRUE ) } for (i in seq_along(along.with = object.list)) { object.list[[i]] <- RenameCells( object = object.list[[i]], new.names = paste( colnames(x = object.list[[i]]), i, sep = '_' )) } } return(object.list) } #' Check List Names #' #' Check to see if a list has names; also check to enforce that all names are #' present and unique #' #' @param x A list #' @param all.unique Require that all names are unique from one another #' @param allow.empty Allow empty (\code{nchar = 0}) names #' @param pass.zero Pass on zero-length lists #' #' @return \code{TRUE} if ..., otherwise \code{FALSE} #' #' @importFrom rlang is_bare_list #' #' @keywords internal #' #' @noRd #' IsNamedList <- function( x, all.unique = TRUE, allow.empty = FALSE, pass.zero = FALSE ) { if (!is_bare_list(x = x)) { return(FALSE) } if (isTRUE(x = pass.zero) && !length(x = x)) { return(TRUE) } n <- names(x = x) named <- !is.null(x = n) if (!isTRUE(x = allow.empty)) { named <- named && all(vapply( X = n, FUN = nchar, FUN.VALUE = integer(length = 1L) )) } if (isTRUE(x = all.unique)) { named <- named && (length(x = n) == length(x = unique(x = n))) } return(named) } #' Test Null Pointers #' #' Check to see if a C++ pointer is a null pointer on the compiled side #' #' @param x An \link[methods:externalptr-class]{external pointer} object #' #' @return \code{TRUE} if \code{x} is a null pointer, otherwise \code{FALSE} #' #' @importFrom methods is #' #' @references \url{https://stackoverflow.com/questions/26666614/how-do-i-check-if-an-externalptr-is-null-from-within-r} #' #' @keywords internal #' #' @noRd #' IsNullPtr <- function(x) { stopifnot(is(object = x, class2 = 'externalptr')) return(.Call('isnull', x)) } #' Test Empty Characters #' #' Check to see if a \code{\link[base]{character}} vector is empty. A character #' is empty if it has no length or an \code{nzchar == FALSE} #' #' @param x A \code{\link[base]{character}} vector #' @param mode Stringency of emptiness test: #' \describe{ #' \item{\dQuote{each}}{Return a single value for each member of \code{x}} #' \item{\dQuote{any}}{Return \code{TRUE} if any member of \code{x} is empty} #' \item{\dQuote{all}}{Return \code{TRUE} if \emph{every} member of \code{x} is #' empty} #' } #' @param na Control how \code{\link[base]{NA}} values are treated: #' \describe{ #' \item{\dQuote{empty}}{Treat \code{NA}s as empty values} #' \item{\dQuote{keep}}{Keep \code{NA} values and treat them as \code{NA}} #' \item{\dQuote{remove}}{Remove \code{NA} values before testing emptiness} #' } #' #' @return If \code{mode} is \dQuote{each}, a vector of logical values denoting #' the emptiness of of each member of \code{x}; otherwise, a singular #' \code{\link[base]{logical}} denoting the overall emptiness of \code{x} #' #' @keywords internal #' #' @noRd #' IsCharEmpty <- function( x, mode = c('each', 'any', 'all'), na = c('empty', 'keep', 'remove') ) { if (!is.character(x = x)) { return(FALSE) } mode <- arg_match(arg = mode) na <- arg_match(arg = na) x <- switch( EXPR = na, empty = x[is.na(x = x)] <- '', remove = x <- x[!is.na(x = x)], x ) if (!length(x = x)) { return(TRUE) } empty <- vapply( X = x, FUN = Negate(f = nzchar), FUN.VALUE = logical(length = 1L), USE.NAMES = FALSE ) empty <- switch( EXPR = mode, any = any(empty), all = all(empty), empty ) return(empty) } #' Update a Class's Package #' #' Swap packages for an object's class definition. As classes move between #' packages, these functions rescope the namespace of the S4 class. This allows #' objects to depend only on the new package for class definitions rather than #' both the new and old packages #' #' @inheritParams s4list #' @param from A vector of one or more packages to limit conversion from #' @param to A character naming the package to search for new class definitions; #' defaults to the package of the function calling this function #' #' @return \code{SwapClassPkg}: \code{x} with an updated S4 class #' definition attribute #' #' @inheritSection s4list S4 Class Definition Attributes #' #' @name classpkg #' @rdname classpkg #' #' @keywords internal #' #' @seealso \code{\link{s4list}} #' #' @noRd #' SwapClassPkg <- function(x, from = NULL, to = NULL) { if (!is_bare_list(x = x)) { return(x) } to <- to[1] %||% environmentName(env = environment( fun = sys.function(which = 1L) )) if (!nchar(x = to) || !paste0('package:', to) %in% search()) { to <- environmentName(env = environment(fun = sys.function(which = 0L))) } for (i in seq_along(along.with = x)) { if (!is.null(x = x[[i]])) { x[[i]] <- SwapClassPkg(x = x[[i]], from = from, to = to) } } if (!IsS4List(x = x)) { return(x) } classdef <- unlist(x = strsplit( x = attr(x = x, which = 'classDef'), split = ':' )) pkg <- classdef[1] cls <- classdef[2] if (is.null(x = from) || pkg %in% from) { pkg <- ifelse( test = is.null(x = getClassDef( Class = cls, package = to, inherits = FALSE )), yes = pkg, no = to ) } attr(x = x, which = 'classDef') <- paste(pkg, cls, sep = ':') return(x) } #' Get the top #' #' @param data Data to pull the top from #' @param num Pull top \code{num} #' @param balanced Pull even amounts of from positive and negative values #' #' @return The top \code{num} #' #' @importFrom utils head tail #' #' @keywords internal #' #' @noRd #' Top <- function(data, num = 20, balanced = FALSE) { nr <- nrow(x = data) if (num > nr) { warning( "Requested number is larger than the number of available items (", nr, "). Setting to ", nr , ".", call. = FALSE ) num <- nr } balanced <- ifelse(test = nr == 1, yes = FALSE, no = balanced) top <- if (isTRUE(x = balanced)) { num <- round(x = num / 2) data <- data[order(data, decreasing = TRUE), , drop = FALSE] positive <- head(x = rownames(x = data), n = num) negative <- rev(x = tail(x = rownames(x = data), n = num)) # remove duplicates if (positive[num] == negative[num]) { negative <- negative[-num] } list(positive = positive, negative = negative) } else { data <- data[rev(x = order(abs(x = data))), , drop = FALSE] top <- head(x = rownames(x = data), n = num) top[order(data[top, ])] } return(top) } #' @rdname classpkg #' #' @return \code{UpdateClassPkg}: \code{object} with the updated #' class definition #' #' @keywords internal #' #' @noRd #' UpdateClassPkg <- function(object, from = NULL, to = NULL) { if (!isS4(object)) { return(object) } obj.list <- S4ToList(object = object) obj.list <- SwapClassPkg(x = obj.list, from = from, to = to) return(ListToS4(x = obj.list)) } #' Update slots in an object #' #' @param object An object to update #' #' @return \code{object} with the latest slot definitions #' #' @importFrom methods slotNames slot #' #' @concept utils #' #' @export #' UpdateSlots <- function(object) { if (!isS4(object)) { return(object) } object.list <- sapply( X = slotNames(x = object), FUN = function(x) { return(tryCatch( expr = slot(object = object, name = x), error = function(...) { return(NULL) } )) }, simplify = FALSE, USE.NAMES = TRUE ) object.list <- Filter(f = Negate(f = is.null), x = object.list) object.list <- c('Class' = class(x = object)[1], object.list) op <- options(Seurat.object.validate = FALSE) on.exit(expr = options(op), add = TRUE) object <- suppressWarnings(expr = do.call(what = 'new', args = object.list)) for (x in setdiff(x = slotNames(x = object), y = names(x = object.list))) { xobj <- slot(object = object, name = x) if (is.vector(x = xobj) && !is.list(x = xobj) && length(x = xobj) == 0) { slot(object = object, name = x) <- vector( mode = class(x = xobj), length = 1L ) } } return(object) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # S4 methods #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% setAs( from = 'Centroids', to = 'Segmentation', def = function(from) { if (is.infinite(x = from)) { stop("Cannot convert shapeless Centroids", call. = FALSE) } return(CreateSegmentation(coords = GetTissueCoordinates( object = from, full = TRUE ))) } ) setAs( from = 'Segmentation', to = 'Centroids', def = function(from) { return(CreateCentroids(coords = GetTissueCoordinates( object = from, full = FALSE ))) } ) SeuratObject/R/zzz.R0000644000176200001440000004026014524302405014026 0ustar liggesusers#' @importFrom sp bbox over #' @importFrom Rcpp evalCpp #' @importFrom Matrix nnzero #' @importFrom progressr progressor #' @importFrom lifecycle deprecated is_present #' @importFrom utils head packageVersion tail upgrade #' @importFrom methods new setClass setClassUnion setGeneric setMethod #' setOldClass setValidity show slot slot<- validObject #' @importFrom rlang abort arg_match arg_match0 caller_env check_installed #' enquo eval_tidy have_name inform is_bare_character is_bare_integerish #' is_bare_list is_bare_numeric is_missing is_na is_named is_quosure #' missing_arg warn #' @importClassesFrom Matrix dgCMatrix CsparseMatrix dsparseMatrix generalMatrix #' dMatrix sparseMatrix compMatrix Matrix #' @useDynLib SeuratObject #' NULL #' @docType package #' @name SeuratObject-package #' @rdname SeuratObject-package #' "_PACKAGE" #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Options #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' \pkg{Seurat} Options #' #' Various options used in \pkg{Seurat} #' #' @section Package Options: #' \subsection{Seurat.coords.short_range}{ #' Defaults to #' \dQuote{\Sexpr[stage=build]{SeuratObject:::Seurat.options$Seurat.coords.short_range}}\cr #' Currently set to \dQuote{\Sexpr[stage=render]{getOption("Seurat.coords.short_range")}} #' } #' \subsection{Seurat.input.sparse_ratio}{ #' Defaults to #' \dQuote{\Sexpr[stage=build]{SeuratObject:::Seurat.options$Seurat.input.sparse_ratio}}\cr #' Currently set to \dQuote{\Sexpr[stage=render]{getOption("Seurat.input.sparse_ratio")}} #' } #' \subsection{Seurat.io.rds.strict}{ #' Defaults to #' \dQuote{\Sexpr[stage=build]{SeuratObject:::Seurat.options$Seurat.io.rds.strict}}\cr #' Currently set to \dQuote{\Sexpr[stage=render]{getOption("Seurat.io.rds.strict")}} #' } #' \subsection{Seurat.object.assay.calcn}{ #' Run \code{CalcN} when adding assay data to a \code{Seurat} object\cr #' Defaults to #' \dQuote{\Sexpr[stage=build]{SeuratObject:::Seurat.options$Seurat.object.assay.calcn}}\cr #' Currently set to \dQuote{\Sexpr[stage=render]{getOption("Seurat.object.assay.calcn")}} #' } #' \subsection{Seurat.object.assay.version}{ #' Defaults to #' \dQuote{\Sexpr[stage=build]{SeuratObject:::Seurat.options$Seurat.object.assay.version}}\cr #' Currently set to \dQuote{\Sexpr[stage=render]{getOption("Seurat.object.assay.version")}} #' } #' \subsection{Seurat.object.assay.v3.missing_layer}{ #' Defaults to #' \dQuote{\Sexpr[stage=build]{SeuratObject:::Seurat.options$Seurat.object.assay.v3.missing_layer}}\cr #' Currently set to \dQuote{\Sexpr[stage=render]{getOption("Seurat.object.assay.v3.missing_layer")}} #' } #' \subsection{Seurat.object.project}{ #' Default project for new \code{\link{Seurat}} objects\cr #' Defaults to #' \dQuote{\Sexpr[stage=build]{SeuratObject:::Seurat.options$Seurat.object.project}}\cr #' Currently set to \dQuote{\Sexpr[stage=render]{getOption("Seurat.object.project")}} #' } #' #' @name SeuratObject-options #' #' @keywords internal #' NULL Seurat.options <- list( Seurat.coords.short_range = 'max', Seurat.input.sparse_ratio = 0.4, Seurat.io.rds.strict = FALSE, Seurat.object.assay.brackets = 'v5', Seurat.object.assay.calcn = NULL, Seurat.object.assay.version = 'v5', Seurat.object.assay.v3.missing_layer = 'matrix', Seurat.object.project = 'SeuratProject', progressr.clear = FALSE ) #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Built With #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% .BuiltWith <- c( R = format(x = getRversion()), Matrix = format(x = packageVersion(pkg = "Matrix")) ) #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Reexports #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' @importFrom future plan #' @export #' future::plan #' @importFrom generics intersect #' @export #' generics::intersect # #' @importFrom Matrix colMeans # #' @export # #' # Matrix::colMeans #' @importFrom progressr handlers #' @export #' progressr::handlers #' @importFrom progressr with_progress #' @export #' progressr::with_progress #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Environments #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% sparse.classes <- new.env() #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Class definitions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% setClassUnion(name = 'OptionalCharacter', members = c('NULL', 'character')) setClassUnion(name = 'OptionalList', members = c('NULL', 'list')) setOldClass(Classes = 'package_version') #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Internal #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' @keywords internal #' #' @noRd #' .AutoRadius <- function(coords) { return(0.01 * mean(x = apply( X = apply(X = coords, MARGIN = 2L, FUN = range), MARGIN = 2L, FUN = diff ))) } #' @keywords internal #' #' @noRd #' .BboxDF <- function(x) { df <- expand.grid(x = x['x', ], y = x['y', ]) df <- df[c(1, 3, 4, 2), ] return(df) } #' Test Intersections of Bounding Boxes #' #' @param i,j \link[sp:bbox]{Bounding boxes} #' @param constraint Type of intersection to perform; choose from: #' \itemize{ #' \item \dQuote{\code{intersect}}: \code{i} must fall at least #' partially within the bounds of \code{j} for the dimensions #' specified by \code{MARGIN} #' \item \dQuote{\code{contained}}: \code{i} must fall completely #' within the bounds of \code{j} for the dimensions specified #' by \code{MARIGN} #' \item \dQuote{\code{overlap}}: \code{i} must fall at least partially #' within \code{j}, or \code{j} must fall at least partially within #' \code{i}, for the dimensions specified by \code{MARGIN}; essentially #' \code{.BboxIntersect(i, j, 'intersect', MARGIN) || .BboxIntersect(j, i, 'intersect', MARGIN)} #' } #' @param MARGIN Direction of intersection; choose from: #' \itemize{ #' \item \code{1L}: intersect along the x-dimension #' \item \code{2L}: intersect along the y-dimension #' \item \code{3L}: intersect along both the x- and y-dimensions #' } #' #' @return \code{TRUE} if \code{i} intersects with \code{j}; #' otherwise \code{FALSE} #' #' @keywords internal #' #' @noRd #' .BboxIntersect <- function( i, j, constraint = c('intersect', 'contained', 'overlap'), MARGIN = 3L ) { constraint <- constraint[1L] constraint <- match.arg(arg = constraint) if (!MARGIN %in% seq.int(from = 1L, to = 3L)) { stop(".MARGIN must be 1, 2, or 3") } else if (MARGIN == 3L) { MARGIN <- seq.int(from = 1L, to = 2L) } check <- vector(mode = 'logical', length = length(x = MARGIN)) names(x = check) <- c('x', 'y')[MARGIN] for (x in names(x = check)) { check[[x]] <- switch( EXPR = constraint, 'intersect' = { (i[x, 'min'] >= j[x, 'min'] && i[x, 'min'] <= j[x, 'max']) || (i[x, 'max'] >= j[x, 'min'] && i[x, 'max'] <= j[x, 'max']) }, 'contained' = i[x, 'min'] >= j[x, 'min'] && i[x, 'max'] <= j[x, 'max'], 'overlap' = { .margin <- c(x = 1L, y = 2L)[x] .BboxIntersect(i = i, j = j, constraint = 'i', MARGIN = .margin) || .BboxIntersect(i = j, j = i, constraint = 'i', MARGIN = .margin) }, stop("Constraint '", constraint, "' not yet implemented") ) } return(all(check)) } .IsDataFrame <- function(x) { return(length(x = class(x = x)) == 1L && inherits(x = x, what = 'data.frame')) } #' Test Future Compatibility with \pkg{Seurat} #' #' Check to see if \pkg{SeuratObject} and/or \pkg{Seurat} are at least a #' specific version or if they're configured to act as if they're a #' specific version (see details below). This allows testing compatibility with #' future requirements for both \pkg{SeuratObject} and \pkg{Seurat} #' #' Blah blah blah #' #' @inheritParams utils::packageVersion #' @param version A version string or object of class #' \code{\link{package_version}} #' #' @return \code{TRUE} if \pkg{SeuratObject} and/or \pkg{Seurat} #' #' @keywords internal #' #' @export #' #' @aliases IsFutureSeurat #' .IsFutureSeurat <- function(version, lib.loc = NULL) { version <- package_version(x = version) opt <- paste0( 'Seurat.future.v', gsub(pattern = '\\.', replacement = '_', x = as.character(x = version)) ) future <- isTRUE(x = getOption(x = opt, default = FALSE)) || packageVersion(pkg = 'SeuratObject', lib.loc = lib.loc) >= version if (requireNamespace('Seurat', quietly = TRUE)) { future <- future || packageVersion(pkg = 'Seurat', lib.loc = lib.loc) >= version } return(future) } .IsNull <- function(x) { return(vapply(X = x, FUN = is.null, FUN.VALUE = logical(length = 1L))) } .MakeNames <- function(x, strict = FALSE, type = c('layers')) { if (isTRUE(x = strict)) { return(make.names(names = x, unique = TRUE)) } type <- type[[1L]] type <- match.arg(arg = type) x <- switch( EXPR = type, layers = { # Remove white spaces x <- gsub(pattern = '[[:space:]]+', replacement = '_', x = x) # Remove illegal characters x <- gsub( pattern = '[\\;\\:\\!\\@\\#\\$\\%\\^\\&\\*\\(\\)\\{\\}\\[]', replacement = '', x = x ) x <- gsub(pattern = '\\]', replacement = '', x = x) x } ) return(x) } #' Create a List with a Serial Comma #' #' @param ... A character vector to join #' @param cnj Conjunction to use for final entry #' @param quote Quote the entries of \code{...}; choose from: #' \itemize{ #' \item \dQuote{\code{single}}: regular single quotes #' \item \dQuote{\code{fancysingle}}: fancy single quotes #' \item \dQuote{\code{double}}: regular double quotes #' \item \dQuote{\code{fancydouble}}: fancy double quotes #' \item \dQuote{\code{none}}: no extra quoting #' } #' #' @return \code{...} arranged into an English list with a serial comma #' when needed #' #' @keywords internal #' #' @seealso \code{\link[base]{sQuote}} #' #' @examples #' .Oxford('cell') #' .Oxford('cell', 'ident') #' .Oxford('cell', 'ident', 'gene') #' #' @noRd #' .Oxford <- function( ..., cnj = c('or', 'and'), quote = c('single', 'fancysingle', 'double', 'fancydouble', 'none') ) { x <- as.character(x = c(...)) cnj <- arg_match(arg = cnj) quote <- arg_match(arg = quote) x <- switch( EXPR = quote, single = sQuote(x = x, q = FALSE), fancysingle = sQuote(x = x, q = TRUE), double = dQuote(x = x, q = FALSE), fancydouble = dQuote(x = x, q = TRUE), x ) if (length(x = x) <= 1L) { return(x) } else if (length(x = x) == 2L) { return(paste(x, collapse = paste0(' ', cnj, ' '))) } return(paste( paste0(paste(x[1:(length(x = x) - 1L)], collapse = ', '), ','), cnj, x[length(x = x)] )) } #' Indexes from Run Length Encodings #' #' Generate an index for subsetting from a \link[base:rle]{run length encoding} #' #' @inheritParams base::lengths #' @param x An \code{\link[base:rle]{rle}} object #' #' @return A list where each entry is the indices a particular value #' #' @keywords internal #' #' @noRd #' .RleIndex <- function(x, use.names = TRUE) { idx <- lapply( X = seq_len(length.out = length(x = x$values)), FUN = function(i) { from <- (x$lengths[i] * i) - (x$lengths[i] - 1L) return(seq.int(from = from, to = from + x$lengths[i] - 1L)) } ) if (isTRUE(x = use.names)) { names(x = idx) <- x$values } return(idx) } #' Round Version Information #' #' @param current A package version #' #' @return ... #' #' @keywords internal #' #' @noRd #' .RoundVersion <- function(current) { current <- as.character(x = numeric_version(x = current, strict = TRUE)) current <- unlist(x = strsplit(x = current, split = '\\.')) if (length(x = current) > 4L) { if (length(x = current) > 4L) { current[4L] <- paste( current[seq.int(from = 4L, to = length(x = current))], collapse = '.' ) current <- current[1:4] } } names(x = current) <- c('major', 'minor', 'patch', 'devel')[seq_along(along.with = current)] if (!is_na(x = current['devel'])) { if (all(current[c('minor', 'patch')] == '9')) { current['major'] <- as.character(x = as.integer(x = current['major']) + 1L) current[c('minor', 'patch')] <- '0' } else if (current['patch'] == '0') { current['minor'] <- as.character(x = as.integer(x = current['minor']) + 1L) current['patch'] <- '0' } else { current['patch'] <- as.character(x = as.integer(x = current['patch']) + 1L) } current <- current[c('major', 'minor', 'patch')] } current <- vapply( X = current, FUN = as.integer, FUN.VALUE = integer(length = 1L), USE.NAMES = TRUE ) if (!is_na(x = current['devel'])) { if (all(current[c('minor', 'patch')] == '9')) { current['major'] <- as.character(x = as.integer(x = current['major']) + 1L) current[c('minor', 'patch')] <- '0' } else if (current['patch'] == '0') { current['minor'] <- as.character(x = as.integer(x = current['minor']) + 1L) current['patch'] <- '0' } else { current['patch'] <- as.character(x = as.integer(x = current['patch']) + 1L) } current <- current[c('major', 'minor', 'patch')] } return(current) } #' Index of Names #' #' Get the index of row- or column-names #' #' @param x A two-dimensional object #' @param names A vector of names to index #' @param MARGIN Either \code{1L} for row-names or \code{2L} for column-names #' #' @return A named integer vector of length \code{length(names)}; the names are #' \code{names} and the values are the index of \code{names} in the row- or #' column-names. If no name is found, uses the lowest available index #' #' @importFrom stats na.omit #' #' @keywords internal #' #' @noRd #' NameIndex <- function(x, names, MARGIN) { if (!MARGIN %in% c(1L, 2L)) { stop("MARGIN must be either 1 or 2", call. = FALSE) } if (!length(x = dim(x = x)) == 2L) { stop("'x' must be a two-dimensional object", call. = FALSE) } nfunc <- list(rownames, colnames)[[MARGIN]] xnames <- nfunc(x = x) if (length(x = names) > length(x = xnames)) { stop( "Too many names requested (", length(x = names), " requested, ", length(x = xnames), " provided)", call. = FALSE ) } idx <- vector(mode = 'integer', length = length(x = names)) names(x = idx) <- names for (i in names) { idx[[i]] <- ifelse( test = i %in% xnames, yes = which(x = xnames == i)[1], no = NA_integer_ ) } idx.na <- which(x = is.na(x = idx)) xind <- setdiff( x = seq_len(length.out = ncol(x = x)), y = na.omit(object = idx) ) for (i in idx.na) { idx[[i]] <- xind[[i]] } return(idx) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Hooks #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% .onAttach <- function(libname, pkgname) { for (i in names(x = .BuiltWith)) { current <- switch(EXPR = i, R = getRversion(), packageVersion(pkg = i)) if (current > .BuiltWith[i]) { msg <- paste( sQuote(x = pkgname), "was built", switch( EXPR = i, R = "under R", paste("with package", sQuote(x = i)) ), .BuiltWith[i], "but the current version is", paste0(current, ';'), "it is recomended that you reinstall ", sQuote(x = pkgname), " as the ABI for", switch(EXPR = i, R = i, sQuote(x = i)), "may have changed" ) packageStartupMessage(paste(strwrap(x = msg), collapse = '\n')) } } } .onLoad <- function(libname, pkgname) { toset <- setdiff(x = names(x = Seurat.options), y = names(x = options())) if (length(x = toset)) { options(Seurat.options[toset]) } setHook( hookName = packageEvent(pkgname = 'Seurat', event = 'onLoad'), value = .SetSeuratCompat ) setHook( hookName = packageEvent(pkgname = 'Signac', event = 'onLoad'), value = .SetSeuratCompat ) setHook( hookName = packageEvent(pkgname = 'Seurat', event = 'attach'), value = .SeuratCompatMessage ) setHook( hookName = packageEvent(pkgname = 'Signac', event = 'attach'), value = .SeuratCompatMessage ) return(invisible(x = NULL)) } SeuratObject/R/fov.R0000644000176200001440000007045314520004201013757 0ustar liggesusers#' @include zzz.R #' @include generics.R #' @include centroids.R #' @include spatial.R #' @include molecules.R #' @include segmentation.R #' NULL #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Class definitions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' The Field of View Object #' #' A modern container for storing coordinates of spatially-resolved single #' cells. Capable of storing multiple cell segmentation boundary masks. #' Supports coordinates for spatially-resolved molecule (FISH) data. #' Compatible with \code{\link{SpatialImage}} #' #' @slot molecules A named list of #' \code{\link[SeuratObject:Molecules-class]{Molecules}} objects defining #' spatially-resolved molecular coordinates #' @slot boundaries A named list of #' \code{\link[SeuratObject:Segmentation-class]{Segmentation}} and #' \code{\link[SeuratObject:Centroids-class]{Centroids}} objects defining #' spatially-resolved boundaries #' @slot assay A character naming the associated assay #' of the spatial coordinates #' @template slot-key #' #' @exportClass FOV #' #' @aliases FOV #' #' @concept fov #' #' @seealso \code{\link{FOV-methods}} #' setClass( Class = 'FOV', contains = 'SpatialImage', slots = list( molecules = 'list', boundaries = 'list' ) ) #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Functions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for Seurat-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' \code{FOV} Methods #' #' Methods for \code{\link{FOV}} objects #' #' @details The following methods are defined for interacting with a #' \code{FOV} object: #' #' @param x,object A \code{\link{FOV}} object #' @param boundary,set Name of segmentation boundary or molecule set to #' extract cell or feature names for; pass \code{NA} to return all #' cells or feature names #' @param i,cells For \code{[[} and \code{[[<-}, the name of a segmentation or #' \dQuote{molecules}; for \code{FetchData}, \code{subset}. and \code{[}, a #' vector of cells to keep #' @param j,features For \code{subset} and \code{[}, a vector of features to #' keep; for \code{[[<-}, not used #' @param value For \code{[[<-}, a replacement #' \code{\link[SeuratObject:Molecules-class]{Molecules}}, #' \code{\link[SeuratObject:Centroids-class]{Centroids}}, or #' \code{\link[SeuratObject:Segmentation-class]{Segmentation}} object; #' otherwise \code{NULL} to remove the boundary stored at \code{i} #' @param ... Arguments passed to other methods #' #' @name FOV-methods #' @rdname FOV-methods #' #' @concept fov #' #' @seealso \code{\link{FOV-class}} #' NULL #' @rdname Boundaries #' @method Boundaries FOV #' @export #' Boundaries.FOV <- function(object, ...) { return(names(x = slot(object = object, name = 'boundaries'))) } #' @template method-cells #' #' @rdname FOV-methods #' @method Cells FOV #' @export #' Cells.FOV <- function(x, boundary = NULL, ...) { boundary <- boundary[1L] %||% DefaultBoundary(object = x) if (is.na(x = boundary)) { return(Reduce( f = union, x = lapply(X = slot(object = x, name = 'boundaries'), FUN = Cells) )) } boundary <- match.arg(arg = boundary, choices = Boundaries(object = x)) return(Cells(x = x[[boundary]])) } #' @rdname CreateFOV #' @method CreateFOV Centroids #' @export #' CreateFOV.Centroids <- function( coords, molecules = NULL, assay = 'Spatial', key = NULL, name = NULL, ... ) { name <- name %||% as.character(x = tolower(x = class(x = coords)[1L])) coords <- list(coords) names(x = coords) <- name return(CreateFOV( coords = coords, molecules = molecules, assay = assay, key = key )) } #' @inheritParams CreateCentroids #' @param type When providing a \code{\link[base]{data.frame}}, specify if #' the coordinates represent a cell segmentation or voxel centroids #' @param molecules A \code{\link[base]{data.frame}} with spatially-resolved #' molecule information or a #' \code{\link[SeuratObject:Molecules-class]{Molecules}} object #' @param assay Name of associated assay #' @param key Key for these spatial coordinates #' @param name When \code{coords} is a \code{\link[base]{data.frame}}, #' \code{\link[SeuratObject:Centroids-class]{Centroids}}, or #' \code{\link[SeuratObject:Segmentation-class]{Segmentation}}, name #' to store coordinates as #' #' @rdname CreateFOV #' @method CreateFOV data.frame #' @export #' CreateFOV.data.frame <- function( coords, type = c('segmentation', 'centroids'), nsides = Inf, radius = NULL, theta = 0L, molecules = NULL, assay = 'Spatial', key = NULL, name = NULL, ... ) { type <- match.arg(arg = type) name <- name %||% type coords <- switch( EXPR = type, 'segmentation' = CreateSegmentation(coords = coords), 'centroids' = CreateCentroids( coords = coords, nsides = nsides, radius = radius, theta = theta ) ) return(CreateFOV( coords = coords, molecules = molecules, assay = assay, key = key )) } #' #' @rdname CreateFOV #' @method CreateFOV list #' @export #' CreateFOV.list <- function( coords, molecules = NULL, assay = 'Spatial', key = NULL, ... ) { # Create a list of Molecules objects if provided; otherwise use an empty list molecules <- molecules %iff% list(molecules = CreateMolecules( coords = molecules, key = 'mols_' )) %||% list() # Create and validate the FOV object obj <- new( Class = 'FOV', boundaries = coords, molecules = molecules, assay = assay, key = key %||% Key(object = assay, quiet = TRUE) ) return(obj) } #' @rdname CreateFOV #' @method CreateFOV Segmentation #' @export #' CreateFOV.Segmentation <- CreateFOV.Centroids #' @rdname Crop #' @method Crop FOV #' @export #' Crop.FOV <- function( object, x = NULL, y = NULL, coords = c("plot", "tissue"), ... ) { if (is.null(x = x) && is.null(x = y)) { return(object) } for (s in names(x = object)) { object[[s]] <- Crop(object = object[[s]], x = x, y = y, coords = coords) } return(object) } #' @rdname Boundaries #' @method DefaultBoundary FOV #' @export #' DefaultBoundary.FOV <- function(object) { return(Boundaries(object = object)[1]) } #' @rdname Boundaries #' @method DefaultBoundary<- FOV #' @export #' "DefaultBoundary<-.FOV" <- function(object, ..., value) { value <- match.arg(arg = value, choices = Boundaries(object = object)) idx <- which(x = Boundaries(object = object) == value) norder <- c( idx, setdiff(x = seq_len(length.out = length(x = object)), y = idx) ) slot(object = object, name = 'boundaries') <- slot( object = object, name = 'boundaries' )[norder] return(object) } #' @template method-features #' #' @rdname FOV-methods #' @method Features FOV #' @export #' Features.FOV <- function(x, set = NULL, ...) { if (!length(x = Molecules(object = x))) { return(NULL) } set <- set[1L] %||% Molecules(object = x)[1L] if (is.na(x = set)) { return(Reduce( f = union, x = lapply(X = slot(object = x, name = 'molecules'), FUN = Features) )) } set <- match.arg(arg = set, choices = Molecules(object = x)) return(Features(x = x[[set]])) } #' @param vars A vector of variables to fetch; can be the name of a #' segmentation boundary, to get tissue coordinates, or molecule names, #' to get molecule coordinates #' @param simplify If only returning either boundary or molecule coordinates, #' return a single data frame instead of a list #' #' @details \code{FetchData}: Fetch boundary and/or molecule coordinates from #' a \code{FOV} object #' #' @return \code{FetchData}: If both molecule and boundary coordinates are #' requested, then a two-length list: #' \itemize{ #' \item \dQuote{\code{molecules}}: A data frame with the molecule coordinates #' requested. If molecules requested are keyed, the keys are preserved in the #' data frame #' \item \dQuote{\code{coordinates}}: A data frame with coordinates from the #' segmentation boundaries requested #' } #' If \code{simplify} is \code{TRUE} and only one data frame is generated, then #' only the data frame is returned. Otherwise, a one-length list is returned #' with the single data frame generated #' #' @rdname FOV-methods #' @method FetchData FOV #' @export #' FetchData.FOV <- function( object, vars, cells = NULL, simplify = TRUE, ... ) { vars.orig <- vars if (is.numeric(x = cells)) { cells <- Cells(x = object)[cells] } else if (is.null(cells)) { cells <- Cells(x = object) } # Find keyed molecules object.keys <- Keys(object = object) keyed.mols <- sapply( X = object.keys, FUN = function(key) { return(grep(pattern = paste0('^', key), x = vars, value = TRUE)) }, simplify = FALSE, USE.NAMES = TRUE ) keyed.mols <- Filter(f = length, x = keyed.mols) mols.fetched <- sapply( X = names(x = keyed.mols), FUN = function(x) { df <- FetchData(object = object[[x]], vars = keyed.mols[[x]], ...) df$molecule <- paste0(Key(object = object[[x]]), df$molecule) return(df) }, simplify = FALSE, USE.NAMES = TRUE ) vars <- setdiff( x = vars, y = unique(x = lapply( X = mols.fetched, FUN = function(df) { return(unique(x = df$molecule)) } )) ) # Find all other molecules unkeyed.mols <- Filter( f = function(x) { return(x %in% Features(x = object, set = NA)) }, x = vars ) if (length(x = unkeyed.mols)) { mols.default <- Molecules(object = object)[1L] unkeyed.fetched <- FetchData( object = object[[mols.default]], vars = unkeyed.mols, ... ) if (mols.default %in% names(x = mols.fetched)) { unkeyed.fetched$molecule <- paste0( Key(object = object[[mols.default]]), unkeyed.fetched$molecule ) vars <- setdiff(x = vars, y = unique(x = unkeyed.mols)) } mols.fetched <- append(x = mols.fetched, values = list(unkeyed.fetched)) } # Assembled the molecules data frame mols.fetched <- do.call(what = 'rbind', args = mols.fetched) rownames(x = mols.fetched) <- NULL vars <- setdiff(x = vars, y = unique(x = mols.fetched$molecule)) # Find all coordinates for the cells requested coords <- Filter( f = function(x) { return(x %in% Boundaries(object = object)) }, x = vars ) coords.fetched <- sapply( X = coords, FUN = function(x) { if (!is.null(x = cells) && !any(cells %in% Cells(x = object, boundary = coords))) { return(NULL) } df <- GetTissueCoordinates(object = subset(x = object[[x]], cells = cells)) df$boundary <- x return(df) }, simplify = FALSE, USE.NAMES = TRUE ) coords.fetched <- do.call(what = 'rbind', args = coords.fetched) rownames(x = coords.fetched) <- NULL vars <- setdiff(x = vars, y = unique(x = coords.fetched$boundary)) # Warn/error about missing vars if (identical(x = vars, y = vars.orig)) { stop("Unable to find any of the provided vars", call. = FALSE) } else if (length(x = vars)) { warning( "The following vars were not found: ", paste(vars, collapse = ', '), call. = FALSE, immediate. = TRUE ) } # Return fetched data data.fetched <- list(molecules = mols.fetched, coordinates = coords.fetched) data.fetched <- Filter(f = Negate(f = is.null), x = data.fetched) if (length(x = data.fetched) == 1L && isTRUE(x = simplify)) { return(data.fetched[[1L]]) } return(data.fetched) } #' @param which Name of segmentation boundary or molecule set #' #' @details \code{GetTissueCoordinates}: Get boundary or molecule #' coordinates from a \code{FOV} object #' #' @return \code{GetTissueCoordinates}: ... #' #' @rdname FOV-methods #' @method GetTissueCoordinates FOV #' @export #' GetTissueCoordinates.FOV <- function(object, which = NULL, ...) { which <- which %||% DefaultBoundary(object = object) which <- match.arg(arg = which, choices = names(x = object)) return(GetTissueCoordinates(object = object[[which]], ...)) } #' @details \code{Keys}: Get the keys of molecule sets contained within a #' \code{FOV} object #' #' @return \code{Keys}: A named vector of molecule set keys; names are the #' names of the molecule sets and values are the keys for the respective #' molecule set #' #' @rdname FOV-methods #' @method Keys FOV #' @export #' Keys.FOV <- function(object, ...) { return(sapply(X = slot(object = object, name = 'molecules'), FUN = Key)) } #' @rdname Boundaries #' @method Molecules FOV #' @export #' Molecules.FOV <- function(object, ...) { return(names(x = slot(object = object, name = 'molecules'))) } #' @details \code{RenameCells}: Update cell names #' #' @inheritParams RenameCells #' #' @return \code{RenameCells}: \code{object} with the cells renamed to #' \code{new.names} #' #' @rdname FOV-methods #' @method RenameCells FOV #' @export #' RenameCells.FOV <- function(object, new.names = NULL, ...) { if (is.null(x = new.names)) { return(object) } new.names <- make.unique(names = new.names) all.cells <- Cells(x = object, boundary = NA) if (length(x = new.names) != length(x = all.cells)) { stop("Cannot partially rename cells", call. = FALSE) } for (boundary in Boundaries(object = object)) { idx <- MatchCells( new = all.cells, orig = Cells(x = object[[boundary]]), ordered = TRUE ) if (!length(x = idx)) { next } object[[boundary]] <- RenameCells( object = object[[boundary]], new.names = new.names[idx] ) } return(object) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for R-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' @importFrom utils .DollarNames #' #' @method .DollarNames FOV #' @export #' .DollarNames.FOV <- function(x, pattern = '') { layers <- as.list(x = names(x = x)) names(x = layers) <- unlist(x = layers) return(.DollarNames(x = layers, pattern = pattern)) } #' @rdname FOV-methods #' @method $ FOV #' @export #' "$.FOV" <- function(x, i, ...) { return(x[[i]]) } #' @rdname FOV-methods #' @method [ FOV #' @export #' "[.FOV" <- function(x, i, j, ...) { if (missing(x = i)) { i <- NULL } if (missing(x = j)) { j <- NULL } return(subset(x = x, cells = i, features = j, ...)) } #' @details \code{$}, \code{[[}: Extract a segmentation boundary #' #' @return \code{$}, \code{[[}: The segmentation boundary or spatially-resolved #' molecule information stored at \code{i} #' #' @rdname FOV-methods #' @method [[ FOV #' @export #' "[[.FOV" <- function(x, i, ...) { i <- match.arg(arg = i, choices = names(x = x)) slot.use <- ifelse( test = i %in% Molecules(object = x), yes = 'molecules', no = 'boundaries' ) return(slot(object = x, name = slot.use)[[i]]) } #' Aggregate Molecules into an Expression Matrix #' #' @param x An object with spatially-resolved molecule information #' @param by Name of a #' \code{\link[SeuratObject:Segmentation-class]{Segmentation}} within #' \code{object} or a #' \code{\link[SeuratObject:Segmentation-class]{Segmentation}} object #' @param set Name of molecule set to aggregate #' @param drop Drop molecules not present in a segmentation; if \code{FALSE}, #' adds a column called \dQuote{\code{boundless}} consisting of molecule counts #' not in a segmentation #' @param ... Arguments passed to other methods #' #' @return An expression matrix #' #' @importFrom stats aggregate #' #' @name aggregate #' @rdname aggregate #' #' @keywords internal #' #' @method aggregate FOV #' @export #' #' @template section-progressr #' @template section-future #' #' @order 1 #' aggregate.FOV <- function(x, by = NULL, set = NULL, drop = TRUE, ...) { # Check molecules set <- set[1L] %||% Molecules(object = x)[1L] if (is.null(x = set)) { stop("No molecules present in this FOV", call. = FALSE) } set <- match.arg(arg = set, choices = Molecules(object = x)) # Check segmentation boundaries by <- by[1L] %||% Filter( f = function(b) { return(inherits(x = x[[b]], what = 'Segmentation')) }, x = Boundaries(object = x) )[1L] if (is.character(x = by)) { by <- x[[by]] } if (!inherits(x = by, what = 'SpatialPolygons')) { stop("'by' is not a segmentation boundary", call. = FALSE) } # TODO: Check bbox intersect # Aggregate return(aggregate(x = x[[set]], by = by, drop = drop, ...)) } #' @method dim FOV #' @export #' dim.FOV <- function(x) { return(c(0, 0)) } #' @details \code{length}: Get the number of segmentation layers in a #' \code{FOV} object #' #' @return \code{length}: The number of segmentation layers #' (\code{\link[SeuratObject:Segmentation-class]{Segmentation}} or #' \code{\link[SeuratObject:Centroids-class]{Centroids}} objects) #' #' @rdname FOV-methods #' @method length FOV #' @export #' length.FOV <- function(x) { return(length(x = slot(object = x, name = 'boundaries'))) } #' @details \code{names}: Get the names of segmentation layers and molecule sets #' #' @return \code{names}: A vector of segmentation boundary and molecule set names #' #' @rdname FOV-methods #' @method names FOV #' @export #' names.FOV <- function(x) { return(c(Boundaries(object = x), Molecules(object = x))) } #' @details \code{subset}, \code{[}: Subset a \code{FOV} object #' #' @return \code{subset}: \code{x} with just the cells and features specified #' #' @rdname FOV-methods #' @method subset FOV #' @export #' subset.FOV <- function(x, cells = NULL, features = NULL, ...) { features <- Features(x = x) %iff% features if (is.null(x = cells) && is.null(x = features)) { return(x) } for (i in Molecules(object = x)) { x[[i]] <- subset(x = x[[i]], features = features) } if (is.numeric(x = cells)) { cells <- Cells(x = x, boundary = NA)[cells] } for (i in Boundaries(object = x)) { x[[i]] <- subset(x = x[[i]], cells = cells) } validObject(object = x) return(x) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Internal #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' Add a Segmentation Boundary #' #' @param x A \code{\link{FOV}} object #' @param i Name to store segmentation boundary as #' @param ... Ignored #' @param value A \code{\link[SeuratObject:Segmentation-class]{Segmentation}} #' or [SeuratObject:Centroids-class]\code{\link{Centroids}} object #' to add #' #' @return \code{x} with \code{value} saved as \code{i} #' #' @importFrom methods as #' #' @keywords internal #' #' @noRd #' .AddSegmentation <- function(x, i, ..., value) { if (i %in% Molecules(object = x)) { stop("'", i, "' already present as molecules", call. = FALSE) } # Check bounding box if (!.BboxIntersect(i = bbox(obj = value), j = bbox(obj = x), constraint = 'overlap')) { stop( "New segmentation boundary does not overlap with existing bounds", call. = FALSE ) } # # Reorder cells # vcells <- MatchCells( # new = Cells(x = value), # orig = Cells(x = x, boundary = NA), # ordered = TRUE # ) # vcells <- c( # vcells, # setdiff( # x = seq.int(from = 1L, to = length(x = Cells(x = value))), # y = vcells # ) # ) # value <- value[vcells] # Check class if (i %in% Boundaries(object = x)) { same.class <- vapply( X = list(x[[i]], value), FUN = inherits, FUN.VALUE = logical(length = 1L), what = 'Segmentation' ) if (length(x = unique(x = same.class)) != 1L) { warning( "Replacement value for ", i, " not of class ", class(x = x[[i]]), call. = FALSE, immediate. = TRUE ) } } # Add segmentation boundary slot(object = x, name = 'boundaries')[[i]] <- value # Reorder cells x <- .OrderCells(object = x) # Validate and return validObject(object = x) return(x) } #' Order cells in an FOV #' #' @param object An \code{\link[SeuratObject:FOV-class]{FOV}} object #' #' @return \code{object} with the cells in each boundary ordered #' #' @keywords internal #' #' @noRd #' .OrderCells <- function(object) { all.cells <- Cells(x = object, boundary = NA) for (b in Boundaries(object = object)) { bcells <- MatchCells( new = Cells(x = object[[b]]), orig = all.cells, ordered = TRUE ) bcells <- c( bcells, setdiff(x = seq_along(along.with = Cells(x = object[[b]])), y = bcells) ) slot(object = object, name = 'boundaries')[[b]] <- object[[b]][bcells] } return(object) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # S4 methods #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' @details \code{[[<-}: Add or remove segmentation layers and molecule #' information to/from a \code{FOV} object #' #' @return \code{[[<-}: Varies depending on the class of \code{value}: #' \itemize{ #' \item If \code{value} is \code{NULL}, returns \code{x} with the boundary #' \code{i} removed; also allows removing \code{molecules}; does not allow #' removing the default segmentation #' \item If \code{value} is a \code{Molecules}, returns \code{x} with #' \code{value} stored in \code{molecules}; requires that \code{i} is #' \dQuote{molecules} #' \item Otherwise, stores \code{value} as a segmentation boundary named \code{i} #' } #' #' @rdname FOV-methods #' setMethod( f = '[[<-', signature = c( x = 'FOV', i = 'character', j = 'missing', value = 'Centroids' ), definition = .AddSegmentation ) #' @rdname FOV-methods #' setMethod( f = '[[<-', signature = c( x = 'FOV', i = 'character', j = 'missing', value = 'Molecules' ), definition = function(x, i, ..., value) { if (i %in% Boundaries(object = x)) { stop("'", i, "' already present as a segmentation boundary") } check.key <- TRUE # Check bounding box for incoming molecules if (!.BboxIntersect(i = bbox(obj = value), j = bbox(obj = x), constraint = 'overlap')) { stop("New molecules do not overlap with existing bounds") } # TODO: Check replacement molecules if (i %in% Molecules(object = x)) { check.key <- Key(object = value) != Key(object = x[[i]]) } if (isTRUE(x = check.key)) { if (Key(object = value) %in% Keys(object = x)) { key <- Key(object = i, quiet = TRUE) while (key %in% Keys(object = x)) { key <- Key(object = RandomName(), quiet = TRUE) } warning( "Duplicate moleculecular keys, changing to '", key, "'", call. = FALSE, immediate. = TRUE ) Key(object = value) <- key } } # Add incoming molecules slot(object = x, name = 'molecules')[[i]] <- value # Validate and return validObject(object = x) return(x) } ) #' @importFrom methods as #' #' @rdname FOV-methods #' setMethod( f = '[[<-', signature = c( x = 'FOV', i = 'character', j = 'missing', value = 'NULL' ), definition = function(x, i, ..., value) { i <- match.arg(arg = i, choices = names(x = x)) if (inherits(x = x[[i]], what = 'Molecules')) { slot(object = x, name = 'molecules')[[i]] <- NULL } else if (i == DefaultBoundary(object = x)) { stop("Cannot remove default boundary", call. = FALSE) } else { slot(object = x, name = 'boundaries')[[i]] <- NULL } validObject(object = x) return(x) } ) #' @rdname FOV-methods #' setMethod( f = '[[<-', signature = c( x = 'FOV', i = 'character', j = 'missing', value = 'Segmentation' ), definition = .AddSegmentation ) setMethod( f = 'bbox', signature = 'FOV', definition = function(obj) { boxes <- lapply(X = slot(object = obj, name = 'boundaries'), FUN = bbox) boxes <- do.call(what = 'cbind', args = boxes) return(bbox(obj = t(x = boxes))) } ) #' @importFrom methods initialize #' setMethod( f = 'initialize', signature = 'FOV', definition = function(.Object, molecules, boundaries, assay, key, ...) { .Object <- callNextMethod(.Object, ...) slot(object = .Object, name = 'molecules') <- molecules slot(object = .Object, name = 'boundaries') <- boundaries slot(object = .Object, name = 'assay') <- assay slot(object = .Object, name = 'key') <- key # Reorder cells in boundaries .Object <- .OrderCells(object = .Object) validObject(object = .Object) return(.Object) } ) #' @importClassesFrom sp Spatial #' @rdname Overlay #' setMethod( f = 'Overlay', signature = c(x = 'FOV', y = 'Spatial'), definition = .OverBbox ) #' @rdname Overlay #' setMethod( f = 'Overlay', signature = c(x = 'FOV', y = 'SpatialPolygons'), definition = function(x, y, invert = FALSE, ...) { for (i in names(x = x)) { x[[i]] <- Overlay(x = x[[i]], y = y, invert = invert, ...) } return(x) } ) #' @rdname Overlay #' setMethod( f = 'Overlay', signature = c(x = 'FOV', y = 'FOV'), definition = .OverBbox ) #' @template method-show #' #' @rdname FOV-methods #' setMethod( f = 'show', signature = c(object = 'FOV'), definition = function(object) { # Show cell information cat( "Spatial coordinates for", length(x = Cells(x = object, boundary = NA)), "cells" ) # Show molecule information if (length(x = Features(x = object, boundary = NA))) { cat(" and", length(x = Features(x = object, boundary = NA)), "molecules\n") cat( " First 10 molecules:", strwrap(x = paste( head(x = Features(x = object, boundary = NA)), collapse = ', ' )) ) } cat("\n") # Show segmentation information cat( "Default segmentation boundary:", DefaultBoundary(object = object), "\n" ) if (length(x = Boundaries(object = object)) > 1L) { segs <- setdiff( x = Boundaries(object = object), y = DefaultBoundary(object = object) ) cat( character(), length(x = segs), "other segmentation boundaries present:", strwrap(x = paste(segs, collapse = ', ')), "\n" ) } # Show associated assay cat("Associated assay:", DefaultAssay(object = object), "\n") # Show key cat("Key:", Key(object = object), "\n") return(invisible(x = NULL)) } ) #' FOV Validity #' #' @templateVar cls FOV #' @template desc-validity #' #' @section Boundary Validation: #' blah #' #' @section Molecule Validation: #' blah #' #' @name FOV-validity #' #' @family fov #' #' @seealso \code{\link[methods]{validObject}} #' setValidity( Class = 'FOV', method = function(object) { if (isFALSE(x = getOption(x = "Seurat.object.validate", default = TRUE))) { warn( message = paste("Not validating", class(x = object)[1L], "objects"), class = 'validationWarning' ) return(TRUE) } valid <- NULL # Check boundaries nlist <- IsNamedList( x = slot(object = object, name = 'boundaries'), pass.zero = TRUE ) if (!isTRUE(x = nlist)) { valid <- c(valid, "'boundaries' must be a named list") } else { all.cells <- Cells(x = object, boundary = NA) for (s in Boundaries(object = object)) { if (!inherits(x = object[[s]], what = c('Segmentation', 'Centroids'))) { valid <- c( valid, "All segmentation boundaries must be either either a 'Segmentation' or 'Centroids' object" ) break } else { cells <- Cells(x = object[[s]]) if (!is.null(cells)) { matched.cells <- MatchCells( new = all.cells, orig = cells, ordered = TRUE ) if (length(x = matched.cells) != length(x = Cells(x = object[[s]]))) { valid <- c( valid, "All segmentation boundaries must have cells" ) break } } else { valid <- c( valid, paste(s, "contains 0 cells") ) break } } } } # Check molecules nlist <- IsNamedList( x = slot(object = object, name = 'molecules'), pass.zero = TRUE ) if (!isTRUE(x = nlist)) { valid <- c(valid, "'molecules' must be a named list") } else { for (m in Molecules(object = object)) { if (!inherits(x = object[[m]], what = 'Molecules')) { valid <- c(valid, "All molecules must inherit from 'Molecules'") break } } } return(valid %||% TRUE) } ) SeuratObject/R/segmentation.R0000644000176200001440000002424714520004201015662 0ustar liggesusers#' @include zzz.R #' @include generics.R #' @importFrom sp coordinates #' @importFrom methods as callNextMethod #' @importClassesFrom sp SpatialPolygons NULL #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Class definitions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' The \code{Segmentation} Class #' #' @family segmentation #' @templateVar cls Segmentation #' @template seealso-methods #' setClass( Class = 'Segmentation', contains = 'SpatialPolygons' ) #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Functions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for Seurat-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' \code{Segmentation} Methods #' #' Methods for \code{\link[SeuratObject:Segmentation-class]{Segmentation}} #' objects #' #' @inheritParams Centroids-methods #' @param x,object,obj A #' \code{\link[SeuratObject:Segmentation-class]{Segmentation}} object #' #' @name Segmentation-methods #' @rdname Segmentation-methods #' #' @section Progress Updates with \pkg{progressr}: #' The following methods use #' \href{https://cran.r-project.org/package=progressr}{\pkg{progressr}} to #' render status updates and progress bars: #' \itemize{ #' \item \code{RenameCells} #' } #' To enable progress updates, wrap #' the function call in \code{\link[progressr]{with_progress}} or run #' \code{\link[progressr:handlers]{handlers(global = TRUE)}} before running #' this function. For more details about \pkg{progressr}, please read #' \href{https://progressr.futureverse.org/articles/progressr-intro.html}{\code{vignette("progressr-intro")}} #' #' @section Parallelization with \pkg{future}: #' The following methods use #' \href{https://cran.r-project.org/package=future}{\pkg{future}} to enable #' parallelization: #' \itemize{ #' \item \code{RenameCells} #' } #' Parallelization strategies can be set using #' \code{\link[future]{plan}}. Common plans include \dQuote{\code{sequential}} #' for non-parallelized processing or \dQuote{\code{multisession}} for parallel #' evaluation using multiple \R sessions; for other plans, see the #' \dQuote{Implemented evaluation strategies} section of #' \code{\link[future:plan]{?future::plan}}. For a more thorough introduction #' to \pkg{future}, see #' \href{https://future.futureverse.org/articles/future-1-overview.html}{\code{vignette("future-1-overview")}} #' #' @concept future #' #' @seealso \code{\link{Segmentation-class}} #' #' @family segmentation #' NULL #' @template method-cells #' #' @rdname Segmentation-methods #' @method Cells Segmentation #' @export #' Cells.Segmentation <- function(x, ...) { return(unname(obj = names(x = x))) } #' @importFrom sp Polygon Polygons SpatialPolygons #' #' @rdname CreateSegmentation #' @method CreateSegmentation data.frame #' @export #' CreateSegmentation.data.frame <- function(coords) { idx <- NameIndex(x = coords, names = c('cell', 'x', 'y'), MARGIN = 2L) xy <- idx[c('x', 'y')] cell.idx <- idx[['cell']] coords <- split(x = coords, f = coords[[cell.idx]]) coords <- sapply( X = coords, FUN = function(x) { cx <- as.matrix(x = x[, xy]) colnames(x = cx) <- c('x', 'y') return(Polygons( srl = list(Polygon(coords = cx)), ID = unique(x = as.character(x = x[[cell.idx]])) )) } ) coords <- SpatialPolygons(Srl = coords) CheckGC() return(as(object = coords, Class = 'Segmentation')) } #' @rdname CreateSegmentation #' @method CreateSegmentation Segmentation #' @export #' CreateSegmentation.Segmentation <- function(coords) { return(coords) } #' @method Crop Segmentation #' @export #' Crop.Segmentation <- .Crop #' @details \code{GetTissueCoordinates}, \code{coordinates}: Get #' tissue coordinates #' #' @inheritParams Centroids-methods #' #' @return \code{GetTissueCoordinates}, \code{coordinates}: A data frame with #' three columns: #' \itemize{ #' \item \dQuote{\code{x}}: the x-coordinate #' \item \dQuote{\code{y}}: the y-coordinate #' \item \dQuote{\code{cell}} or \dQuote{\code{ID}}: the cell name #' } #' If \code{full} is \code{TRUE}, then each coordinate will indicate a vertex #' for the cell polygon; otherwise, each coordinate will indicate a centroid #' for the cell. Note: \code{GetTissueCoordinates} .... #' #' @rdname Segmentation-methods #' @method GetTissueCoordinates Segmentation #' @export #' GetTissueCoordinates.Segmentation <- function(object, full = TRUE, ...) { coords <- coordinates(obj = object, full = full, ...) colnames(x = coords) <- c('x', 'y', 'cell') rownames(x = coords) <- NULL return(coords) } #' @details \code{RenameCells}: Update cell names #' #' @inheritParams RenameCells #' #' @return \code{RenameCells}: \code{object} with the cells renamed to #' \code{new.names} #' #' @importFrom future.apply future_mapply #' #' @rdname Segmentation-methods #' @method RenameCells Segmentation #' @export #' RenameCells.Segmentation <- function(object, new.names = NULL, ...) { if (is.null(x = new.names)) { return(object) } new.names <- make.unique(names = new.names) if (length(x = new.names) != length(x = Cells(x = object))) { stop("Cannot partially rename segmentation cells", call. = FALSE) } names(x = slot(object = object, name = 'polygons')) <- new.names p <- progressor(along = slot(object = object, name = 'polygons')) slot(object = object, name = 'polygons') <- future_mapply( FUN = function(polygon, name) { slot(object = polygon, name = 'ID') <- name p() return(polygon) }, polygon = slot(object = object, name = 'polygons'), name = new.names, SIMPLIFY = FALSE, USE.NAMES = TRUE ) return(object) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for R-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' @template method-lengths #' #' @rdname Segmentation-methods #' @method lengths Segmentation #' @export #' lengths.Segmentation <- function(x, use.names = TRUE) { return(rle(x = GetTissueCoordinates(object = x, full = TRUE)$cell)) } #' @details \code{subset}, \code{[}: Subset a \code{Segmentation} object to #' certain cells #' #' @return \code{subset}, \code{[}: \code{x} subsetted to the cells specified #' by \code{cells}/\code{i} #' #' @rdname Segmentation-methods #' @method subset Segmentation #' @export #' subset.Segmentation <- function(x, cells = NULL, ...) { if (is.null(x = cells)) { return(x) } if (is.numeric(x = cells)) { cells <- Cells(x = x)[cells] cells <- MatchCells(new = Cells(x = x), orig = cells, ordered = TRUE) } else { cells <- intersect(Cells(x), cells) } if (!length(x = cells)) { stop("None of the requested cells found") } x <- x[cells] return(as(object = x, Class = 'Segmentation')) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Internal #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # S4 methods #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' @rdname Segmentation-methods #' setMethod( f = '[', signature = c(x = 'Segmentation'), definition = function(x, i, j, ..., drop = TRUE) { x <- callNextMethod() return(as(object = x, Class = 'Segmentation')) } ) #' @rdname Segmentation-methods #' setMethod( f = 'coordinates', signature = c(obj = 'Segmentation'), definition = function(obj, full = TRUE, ...) { if (!isTRUE(x = full)) { coords <- as.data.frame(x = callNextMethod(obj = obj)) coords$cell <- Cells(x = obj) return(coords) } coords <- lapply( X = slot(object = obj, name = 'polygons'), FUN = function(x) { polys <- lapply( X = slot(object = x, name = 'Polygons'), FUN = slot, name = 'coords' ) polys <- as.data.frame(x = do.call(what = 'rbind', args = polys)) colnames(x = polys) <- c('x', 'y') polys$ID <- slot(object = x, name = 'ID') return(polys) } ) coords <- do.call(what = 'rbind', args = coords) rownames(x = coords) <- NULL return(coords) } ) setMethod( f = 'over', signature = c(x = 'Segmentation', y = 'SpatialPolygons'), definition = function(x, y, returnList = FALSE, fn = NULL, ...) { deprecate_stop( when = '5.0.0', what = 'over()', details = "Future integration with `sf` is on the roadmap with no current ETA" ) check_installed(pkg = 'sf') return(over( x = as(object = x, Class = 'sf'), y = as(object = y, Class = 'sf'), sparse = FALSE, returnList = returnList, fn = fn, ... )) } ) #' @rdname Overlay #' @export #' setMethod( f = 'Overlay', signature = c(x = 'Segmentation', y = 'SpatialPolygons'), definition = function(x, y, invert = FALSE, ...) { check_installed(pkg = 'sf', reason = 'to overlay spatial information') idx <- sf::st_intersects( x = as(object = x, Class = 'sf'), y = as(object = y, Class = 'sf'), sparse = FALSE ) idx <- which(x = idx) names_in_sf_object1 <- if (!is.null(x = row.names(x = x))) { row.names(x = x)[idx] } else { x$id[idx] } idx <- setNames( object = rep.int(x = TRUE, times = length(x = idx)), nm = names_in_sf_object1 ) if (!length(x = idx)) { warn("The selected region does not contain any cell segmentations") return(NULL) } names(x = idx) <- vapply( X = strsplit(x = names(x = idx), split = '\\.'), FUN = '[[', FUN.VALUE = character(length = 1L), 1L, USE.NAMES = FALSE ) cells <- if (isTRUE(x = invert)) { setdiff(x = Cells(x = x), y = names(x = idx)) } else { names(x = idx) } x <- x[cells] return(x) } ) #' @template method-show #' #' @rdname Segmentation-methods #' setMethod( f = 'show', signature = c(object = 'Segmentation'), definition = function(object) { cat("A spatial segmentation for", length(x = object), "cells\n") } ) SeuratObject/R/generics.R0000644000176200001440000011773014520004201014764 0ustar liggesusers#' @include zzz.R #' NULL #' Assay Class Label #' #' @param object A \code{\link{StdAssay}} object #' #' @return The assay class label for \code{object} #' #' @keywords internal #' #' @export .AssayClass #' .AssayClass <- function(object) { UseMethod(generic = '.AssayClass', object = object) } #' Calculate nCount and nFeature #' #' @template param-dots-method #' @param object An assay-like object #' #' @return A named list with ... #' #' @keywords internal #' #' @export .CalcN #' #' @examples #' calcn <- .CalcN(pbmc_small[["RNA"]]) #' head(as.data.frame(calcn)) #' .CalcN <- function(object, ...) { UseMethod(generic = '.CalcN', object = object) } #' Get the Package that Defines a Class #' #' @param object An object #' #' @return The package that defines the class of \code{object} #' #' @keywords internal #' #' @export .ClassPkg #' #' @examples #' .ClassPkg(pbmc_small) #' .ClassPkg <- function(object) { UseMethod(generic = '.ClassPkg', object = object) } #' Generic Assay Creation #' #' Create an assay object; runs a standardized filtering scheme that #' works regardless of the direction of the data (eg. cells as columns #' and features as rows or vice versa) and creates an assay object based #' on the initialization scheme defined for \code{\link{StdAssay}}-derived #' class \code{type} #' #' @param counts A two-dimensional expression matrix #' @param min.cells Include features detected in at least this many cells; #' will subset the counts matrix as well. To reintroduce excluded features, #' create a new object with a lower cutoff #' @param min.features Include cells where at least this many features #' are detected #' @param cells Vector of cell names #' @param features Vector of feature names #' @param type Type of assay object to create; must be the name of a class #' that's derived from \code{\link{StdAssay}} #' @param ... Extra parameters passed to \code{\link[methods]{new}} for #' assay creation; used to set slots not defined by \code{\link{StdAssay}} #' #' @return An object of class \code{type} with a layer named \code{layer} #' containing the data found in \code{counts} #' #' @keywords internal #' #' @export .CreateStdAssay #' #' @concept assay #' .CreateStdAssay <- function( counts, min.cells = 0, min.features = 0, cells = NULL, features = NULL, transpose = FALSE, type = 'Assay5', ... ) { UseMethod(generic = '.CreateStdAssay', object = counts) } #' Disk Loading Function #' #' Generate a function to load a matrix from an on-disk file #' #' @inheritParams .FilePath #' #' @return A one-length character that defines a function to load a matrix from #' a file #' #' @keywords internal #' #' @export .DiskLoad #' .DiskLoad <- function(x) { UseMethod(generic = '.DiskLoad', object = x) } #' Find a File Path #' #' @param x A file-backed object #' #' @return The path to the file that backs \code{x}; if \code{x} is not a #' file-backed object, returns \code{NULL} #' #' @keywords internal #' #' @export .FilePath #' .FilePath <- function(x) { UseMethod(generic = '.FilePath', object = x) } #' Get the Margin of an Object #' #' @param x An object #' #' @return The margin, eg. \code{1} for rows or \code{2} for columns #' #' @keywords internal #' #' @export .MARGIN #' .MARGIN <- function(x, ...) { UseMethod(generic = '.MARGIN', object = x) } #' Combine and Select Features #' #' @template param-dots-method #' @param object An object #' #' @return A vector of features selected #' #' @keywords internal #' #' @export .SelectFeatures #' .SelectFeatures <- function(object, ...) { UseMethod(generic = '.SelectFeatures', object = object) } #' Add in metadata associated with either cells or features. #' #' Adds additional data to the object. Can be any piece of information #' associated with a cell (examples include read depth, alignment rate, #' experimental batch, or subpopulation identity) or feature (ENSG name, #' variance). To add cell level information, add to the Seurat object. If adding #' feature-level metadata, add to the Assay object (e.g. \code{object[["RNA"]]}) #' #' @param object An object #' @param metadata A vector, list, or data.frame with metadata to add #' @param col.name A name for meta data if not a named list or data.frame #' #' @return \code{object} with metadata added #' #' @rdname AddMetaData #' @export AddMetaData #' #' @aliases SeuratAccess #' #' @concept seurat #' #' @examples #' cluster_letters <- LETTERS[Idents(object = pbmc_small)] #' names(cluster_letters) <- colnames(x = pbmc_small) #' pbmc_small <- AddMetaData( #' object = pbmc_small, #' metadata = cluster_letters, #' col.name = 'letter.idents' #' ) #' head(x = pbmc_small[[]]) #' AddMetaData <- function(object, metadata, col.name = NULL) { UseMethod(generic = 'AddMetaData', object = object) } #' Coerce to a \code{Graph} Object #' #' Convert a \code{\link[base]{matrix}} (or \code{\link[Matrix]{Matrix}}) to #' a \code{\link{Graph}} object #' #' @template param-dots-ignored #' @param x The matrix to convert #' #' @return A \code{\link{Graph}} object #' #' @rdname as.Graph #' @export as.Graph #' #' @family graph #' as.Graph <- function(x, ...) { UseMethod(generic = "as.Graph", object = x) } #' Convert Segmentation Layers #' #' @inheritParams CreateCentroids #' @template param-dots-method #' @param x An object #' #' @return \code{as.Centroids}: A #' \code{\link[SeuratObject:Centroids-class]{Centroids}} object #' #' @export #' #' @concept spatial #' as.Centroids <- function(x, nsides = NULL, radius = NULL, theta = NULL, ...) { UseMethod(generic = "as.Centroids", object = x) } #' Coerce to a \code{Neighbor} Object #' #' Convert objects to \code{\link{Neighbor}} objects #' #' @template param-dots-method #' @param x An object to convert to \code{\link{Neighbor}} #' #' @return A \code{\link{Neighbor}} object #' #' @rdname as.Neighbor #' @export as.Neighbor #' #' @concept neighbor #' as.Neighbor <- function(x, ...) { UseMethod(generic = 'as.Neighbor', object = x) } #' @return \code{as.Segmentation}: A #' \code{\link[SeuratObject:Segmentation-class]{Segmentation}} object #' #' @rdname as.Centroids #' @export #' as.Segmentation <- function(x, ...) { UseMethod(generic = 'as.Segmentation', object = x) } #' Coerce to a \code{Seurat} Object #' #' Convert objects to Seurat objects #' #' @template param-dots-method #' @param x An object to convert to class \code{Seurat} #' #' @return A \code{\link{Seurat}} object generated from \code{x} #' #' @rdname as.Seurat #' @export as.Seurat #' #' @concept seurat #' as.Seurat <- function(x, ...) { UseMethod(generic = 'as.Seurat', object = x) } #' Cast to Sparse #' #' Convert dense objects to sparse representations #' #' @template param-dots-method #' @param x An object #' #' @return A sparse representation of the input data #' #' @rdname as.sparse #' @export as.sparse #' #' @concept utils #' as.sparse <- function(x, ...) { UseMethod(generic = 'as.sparse', object = x) } #' Query Specific Object Types #' #' List the names of \code{\link{Assay}}, \code{\link{DimReduc}}, #' \code{\link{Graph}}, \code{\link{Neighbor}} objects #' #' @template param-dots-ignored #' @param object A \code{\link{Seurat}} object #' @param slot Name of component object to return #' #' @return If \code{slot} is \code{NULL}, the names of all component objects #' in this \code{Seurat} object. Otherwise, the specific object specified #' #' @rdname ObjectAccess #' #' @export #' #' @concept data-access #' #' @examples #' Assays(pbmc_small) #' Assays <- function(object, ...) { UseMethod(generic = "Assays", object = object) } #' Get, Set, and Query Segmentation Boundaries #' #' @template param-dots-method #' @param object An object #' #' @name Boundaries #' @return \code{Boundaries}: The names of all segmentation boundaries present #' within \code{object} #' #' @rdname Boundaries #' @export #' #' @concept spatial #' Boundaries <- function(object, ...) { UseMethod(generic = 'Boundaries', object = object) } #' Cast Assay Layers #' #' Cast layers in v5 assays to other classes #' #' @param object An object #' @param to Either a class name or a function that takes a layer and returns #' the same layer as a new class #' @param ... If \code{to} is a function, arguments passed to \code{to} #' #' @return \code{object} with the layers cast to class specified by \code{to} #' #' @export #' #' @concept assay5 #' CastAssay <- function(object, to, ...) { UseMethod(generic = 'CastAssay', object = object) } #' Cell and Feature Names #' #' Get the cell and feature names of an object #' #' @template param-dots-method #' @param x An object #' #' @return \code{Cell}: A vector of cell names #' #' @rdname Cells #' @export Cells #' #' @concept data-access #' @family dimnames #' #' @examples #' Cells(x = pbmc_small) #' Cells <- function(x, ...) { UseMethod(generic = 'Cells', object = x) } #' Check Matrix Validity #' #' @template param-dots-method #' @param object A matrix #' @param checks Type of checks to perform, choose one or more from: #' \itemize{ #' \item \dQuote{\code{infinite}}: Emit a warning if any value is infinite #' \item \dQuote{\code{logical}}: Emit a warning if any value is a logical #' \item \dQuote{\code{integer}}: Emit a warning if any value is \emph{not} #' an integer #' \item \dQuote{\code{na}}: Emit a warning if any value is an \code{NA} #' or \code{NaN} #' } #' #' @return Emits warnings for each test and invisibly returns \code{NULL} #' #' @name CheckMatrix #' @rdname CheckMatrix #' #' @keywords internal #' #' @export #' #' @concept utils #' CheckMatrix <- function(object, checks, ...) { UseMethod(generic = 'CheckMatrix', object = object) } #' Get SeuratCommands #' #' Pull information on previously run commands in the Seurat object. #' #' @template param-dots-method #' @param object An object #' #' @return Either a SeuratCommand object or the requested parameter value #' #' @rdname Command #' @export Command #' #' @concept data-access #' Command <- function(object, ...) { UseMethod(generic = 'Command', object = object) } #' Create a \code{\link[SeuratObject:Centroids-class]{Centroids}} Objects #' #' @param coords The coordinates of cell/spot centroids #' @param nsides The number of sides to represent cells/spots; pass #' \code{\link[base]{Inf}} to plot as circles #' @param radius Radius of shapes when plotting #' @param theta Angle to adjust shapes when plotting #' #' @return A \code{\link[SeuratObject:Centroids-class]{Centroids}} object #' #' @export #' #' @concept spatial #' CreateCentroids <- function(coords, nsides, radius, theta) { UseMethod(generic = 'CreateCentroids', object = coords) } #' Create Spatial Coordinates #' #' @template param-dots-method #' @param coords Spatial coordinates #' #' @return A \code{\link{FOV}} object #' #' @export #' #' @concept spatial #' #' @seealso \code{\link{FOV-class}} #' CreateFOV <- function(coords, ...) { UseMethod(generic = 'CreateFOV', object = coords) } #' Create a \code{\link{Molecules}} Object #' #' @template param-dots-method #' @param coords Spatial coordinates for molecules; should be a data frame #' with three columns: #' \itemize{ #' \item \dQuote{\code{x}}: x-coordinates for each molecule #' \item \dQuote{\code{y}}: y-coordinates for each molecule #' \item \dQuote{\code{gene}}: gene name for each molecule #' } #' #' @return A \code{\link{Molecules}} object #' #' @export #' #' @concept spatial #' CreateMolecules <- function(coords, ...) { UseMethod(generic = 'CreateMolecules', object = coords) } #' Create a \code{\link[SeuratObject:Segmentation-class]{Segmentation}} Objects #' #' @param coords The coordinates of cell segmentations #' #' @return A \code{\link[SeuratObject:Segmentation-class]{Segmentation}} object #' #' @export #' #' @concept spatial #' CreateSegmentation <- function(coords) { UseMethod(generic = 'CreateSegmentation', object = coords) } #' Create a \code{Seurat} object #' #' Create a \code{Seurat} object from raw data #' #' @inheritParams CreateAssayObject #' @template param-dots-method #' @param counts Either a \code{\link[base]{matrix}}-like object with #' unnormalized data with cells as columns and features as rows or an #' \code{\link{Assay}}-derived object #' @param project \link{Project} name for the \code{Seurat} object #' @param assay Name of the initial assay #' @param names.field For the initial identity class for each cell, choose this #' field from the cell's name. E.g. If your cells are named as #' BARCODE_CLUSTER_CELLTYPE in the input matrix, set \code{names.field} to 3 to #' set the initial identities to CELLTYPE. #' @param names.delim For the initial identity class for each cell, choose this #' delimiter from the cell's column name. E.g. If your cells are named as #' BARCODE-CLUSTER-CELLTYPE, set this to \dQuote{-} to separate the cell name #' into its component parts for picking the relevant field. #' @param meta.data Additional cell-level metadata to add to the Seurat object. #' Should be a \code{\link[base]{data.frame}} where the rows are cell names and #' the columns are additional metadata fields. Row names in the metadata need #' to match the column names of the counts matrix. #' #' @note In previous versions (<3.0), this function also accepted a parameter to #' set the expression threshold for a \sQuote{detected} feature (gene). This #' functionality has been removed to simplify the initialization #' process/assumptions. If you would still like to impose this threshold for #' your particular dataset, simply filter the input expression matrix before #' calling this function. #' #' @return A \code{\link{Seurat}} object #' #' @rdname CreateSeuratObject #' @export #' #' @concept seurat #' #' @examples #' \dontrun{ #' pbmc_raw <- read.table( #' file = system.file('extdata', 'pbmc_raw.txt', package = 'Seurat'), #' as.is = TRUE #' ) #' pbmc_small <- CreateSeuratObject(counts = pbmc_raw) #' pbmc_small #' } #' CreateSeuratObject <- function( counts, assay = 'RNA', names.field = 1, names.delim = '_', meta.data = NULL, project = 'CreateSeuratObject', ... ) { UseMethod(generic = 'CreateSeuratObject', object = counts) } #' Crop Coordinates #' #' @template param-dots-method #' @param object An object #' @param x,y Range to crop x/y limits to; if \code{NULL}, uses full range of #' \code{x}/\code{y} #' @param coords Coordinate system to execute crop; choose from: #' \itemize{ #' \item \dQuote{\code{plot}}: Coordinates as shown when plotting #' \item \dQuote{\code{tissue}}: Coordinates from #' \code{\link{GetTissueCoordinates}} #' } #' #' @return \code{object} cropped to the region specified by \code{x} #' and \code{y} #' #' @export #' #' @concept spatial #' Crop <- function(object, x = NULL, y = NULL, coords = c('plot', 'tissue'), ...) { UseMethod(generic = 'Crop', object = object) } #' Default Assay #' #' Get and set the default assay #' #' @template param-dots-method #' @param object An object #' #' @return \code{DefaultAssay}: The name of the default assay #' #' @rdname DefaultAssay #' @export DefaultAssay #' #' @concept data-access #' DefaultAssay <- function(object, ...) { UseMethod(generic = 'DefaultAssay', object = object) } #' @param value Name of assay to set as default #' #' @return \code{DefaultAssay<-}: An object with the default assay updated #' #' @rdname DefaultAssay #' @export DefaultAssay<- #' "DefaultAssay<-" <- function(object, ..., value) { UseMethod(generic = 'DefaultAssay<-', object = object) } #' @return \code{DefaultBoundary}: The name of the default #' segmentation boundary #' #' @rdname Boundaries #' #' @export #' DefaultBoundary <- function(object) { UseMethod(generic = 'DefaultBoundary', object = object) } #' @param value The name of a segmentation boundary to set as default #' #' @return \code{DefaultBoundary<-}: \code{object} with the default #' segmentation boundary set to \code{value} #' #' @rdname Boundaries #' #' @export #' "DefaultBoundary<-" <- function(object, ..., value) { UseMethod(generic = 'DefaultBoundary<-', object = object) } #' Get and Set the Default FOV #' #' @template param-dots-method #' @param object A \code{\link{Seurat}} Object #' #' @return \code{DefaultFOV}: The name of the default \code{\link{FOV}} #' #' @name DefaultFOV #' @rdname DefaultFOV #' #' @export #' #' @concept spatial #' DefaultFOV <- function(object, ...) { UseMethod(generic = 'DefaultFOV', object = object) } #' @param value The name of the \code{\link{FOV}} to set as the default #' #' @return \code{DefaultFOV<-}: \code{object} with the default FOV set #' to \code{value} #' #' @rdname DefaultFOV #' #' @export #' "DefaultFOV<-" <- function(object, ..., value) { UseMethod(generic = 'DefaultFOV<-', object = object) } #' Default Layer #' #' Get and set the default layer #' #' @template param-dots-method #' @param object An object #' #' @return \code{DefaultLayer}: The name of the default layer #' #' @rdname DefaultLayer #' @export DefaultLayer #' #' @concept assay5 #' DefaultLayer <- function(object, ...) { UseMethod(generic = 'DefaultLayer', object = object) } #' @param value Name of layer to set as default #' #' @return \code{DefaultLayer<-}: An object with the default layer updated #' #' @rdname DefaultLayer #' @export DefaultLayer<- #' "DefaultLayer<-" <- function(object, ..., value) { UseMethod(generic = 'DefaultLayer<-', object = object) } #' Get the Neighbor nearest neighbors distance matrix #' #' @template param-dots-method #' @param object An object #' #' @return The distance matrix #' #' @rdname Distances #' @export Distances #' #' @concept data-access #' Distances <- function(object, ...) { UseMethod(generic = 'Distances', object = object) } #' Get Cell Embeddings #' #' @template param-dots-method #' @param object An object #' #' @return The embeddings matrix #' #' @rdname Embeddings #' @export Embeddings #' #' @concept data-access #' Embeddings <- function(object, ...) { UseMethod(generic = 'Embeddings', object = object) } #' Access cellular data #' #' Retrieves data (feature expression, PCA scores, metrics, etc.) for a set #' of cells in a Seurat object #' #' @template param-dots-method #' @param object An object #' #' @export FetchData #' #' @concept data-access #' FetchData <- function(object, ...) { UseMethod(generic = 'FetchData', object = object) } #' @return \code{Features}: A vector of feature names #' #' @rdname Cells #' @export Features #' Features <- function(x, ...) { UseMethod(generic = 'Features', object = x) } #' Get and Set Assay Data #' #' General accessor and setter functions for \code{\link{Assay}} objects. #' \code{GetAssayData} can be used to pull information from any of the #' expression matrices (eg. \dQuote{counts}, \dQuote{data}, or #' \dQuote{scale.data}). \code{SetAssayData} can be used to replace one of these #' expression matrices #' #' @template param-dots-method #' @param object An object #' @param layer Name of layer to get or set #' @param slot \Sexpr[stage=build,results=rd]{lifecycle::badge("deprecated")} Specific assay data to get or set #' #' @return \code{GetAssayData}: returns the specified assay data #' #' @template lifecycle-superseded #' #' @section Lifecycle: #' #' \code{GetAssayData} and \code{SetAssayData} have been superseded. To fetch #' expression matrices, use \code{\link{LayerData}}; to set expression data, #' use \code{\link{LayerData<-}} #' #' @name AssayData #' @rdname AssayData #' @export GetAssayData #' #' @order 1 #' #' @concept data-access #' GetAssayData <- function(object, ...) { UseMethod(generic = 'GetAssayData', object = object) } #' Get image data #' #' @template param-dots-method #' @param object An object #' @param mode How to return the image; should accept one of \dQuote{grob}, #' \dQuote{raster}, \dQuote{plotly}, or \dQuote{raw} #' #' @return Image data, varying depending on the value of \code{mode}: #' \describe{ #' \item{\dQuote{grob}}{ #' An object representing image data inheriting from \code{grob} objects #' (eg. \code{rastergrob}) #' } #' \item{\dQuote{raster}}{An object of class \code{raster}} #' \item{\dQuote{plotly}}{ #' A list with image data suitable for Plotly rendering, see #' \code{\link[plotly:layout]{plotly::layout}} for more details #' } #' \item{\dQuote{raw}}{The raw image data as stored in the object} #' } #' #' @seealso \code{\link[plotly]{layout}} #' #' @rdname GetImage #' @export GetImage #' #' @concept data-access #' GetImage <- function(object, mode = c('grob', 'raster', 'plotly', 'raw'), ...) { mode <- mode[1] mode <- match.arg(arg = mode) UseMethod(generic = 'GetImage', object = object) } #' Get tissue coordinates #' #' @template param-dots-method #' @param object An object #' #' @return A data frame with tissue coordinates #' #' @rdname GetTissueCoordinates #' @export GetTissueCoordinates #' #' @concept data-access #' GetTissueCoordinates <- function(object, ...) { UseMethod(generic = 'GetTissueCoordinates', object = object) } #' Highly Variable Features #' #' Get and set variable feature information for an \code{\link{Assay}} object. #' \code{HVFInfo} and \code{VariableFeatures} utilize generally variable #' features, while \code{SVFInfo} and \code{SpatiallyVariableFeatures} are #' restricted to spatially variable features #' #' @template param-dots-method #' @param object An object #' @param method Which method to pull. For \code{HVFInfo} and #' \code{VariableFeatures}, choose one from one of the #' following: #' \itemize{ #' \item \dQuote{vst} #' \item \dQuote{sctransform} or \dQuote{sct} #' \item \dQuote{mean.var.plot}, \dQuote{dispersion}, \dQuote{mvp}, or #' \dQuote{disp} #' } #' For \code{SVFInfo} and \code{SpatiallyVariableFeatures}, choose from: #' \itemize{ #' \item \dQuote{markvariogram} #' \item \dQuote{moransi} #' } #' @param status Add variable status to the resulting data frame #' @param selection.method \Sexpr[stage=build,results=rd]{lifecycle::badge("deprecated")} #' #' @return \code{HVFInfo}: A data frame with feature means, dispersion, and #' scaled dispersion #' #' @rdname VariableFeatures #' @export HVFInfo #' #' @order 1 #' #' @concept data-access #' HVFInfo <- function(object, method, status = FALSE, ...) { UseMethod(generic = 'HVFInfo', object = object) } #' Get, set, and manipulate an object's identity classes #' #' @param x,object An object #' @param ... Arguments passed to other methods; for \code{RenameIdents}: named #' arguments as \code{old.ident = new.ident}; for \code{ReorderIdent}: arguments #' passed on to \code{\link{FetchData}} #' #' @return \code{Idents}: The cell identities #' #' @rdname Idents #' @export Idents #' #' @concept seurat #' #' @examples #' # Get cell identity classes #' Idents(pbmc_small) #' Idents <- function(object, ... ) { UseMethod(generic = 'Idents', object = object) } #' @param value The name of the identities to pull from object metadata or the #' identities themselves #' #' @return \code{Idents<-}: \code{object} with the cell identities changed #' #' @rdname Idents #' @export Idents<- #' #' @examples #' # Set cell identity classes #' # Can be used to set identities for specific cells to a new level #' Idents(pbmc_small, cells = 1:4) <- 'a' #' head(Idents(pbmc_small)) #' #' # Can also set idents from a value in object metadata #' colnames(pbmc_small[[]]) #' Idents(pbmc_small) <- 'RNA_snn_res.1' #' levels(pbmc_small) #' "Idents<-" <- function(object, ..., value) { UseMethod(generic = 'Idents<-', object = object) } #' Get Neighbor algorithm index #' #' @template param-dots-method #' @param object An object #' #' @return Returns the value in the alg.idx slot of the Neighbor object #' #' @rdname NNIndex #' @export Index #' #' @concept data-access #' Index <- function(object, ...) { UseMethod(generic = "Index", object = object) } #' @param value The index to store #' #' @return \code{Idents<-}: A Neighbor object with the index stored #' #' @rdname NNIndex #' @export Index<- #' "Index<-" <- function(object, ..., value) { UseMethod(generic = 'Index<-', object = object) } #' Get Neighbor nearest neighbor index matrices #' #' @template param-dots-method #' @param object An object #' #' @return A matrix with the nearest neighbor indices #' #' @rdname Indices #' @export Indices #' #' @concept data-access #' Indices <- function(object, ...) { UseMethod(generic = "Indices", object = object) } #' Is an object global/persistent? #' #' Typically, when removing \code{Assay} objects from an \code{Seurat} object, #' all associated objects (eg. \code{DimReduc}, \code{Graph}, and #' \code{SeuratCommand} objects) #' are removed as well. If an associated object is marked as global/persistent, #' the associated object will remain even if its original assay was deleted #' #' @template param-dots-method #' @param object An object #' #' @return \code{TRUE} if the object is global/persistent otherwise \code{FALSE} #' #' @rdname IsGlobal #' @export IsGlobal #' #' @concept data-access #' #' @examples #' IsGlobal(pbmc_small[['pca']]) #' IsGlobal <- function(object, ...) { UseMethod(generic = 'IsGlobal', object = object) } #' Check if a matrix is empty #' #' Takes a matrix and asks if it's empty (either 0x0 or 1x1 with a value of NA) #' #' @param x A matrix #' #' @return Whether or not \code{x} is empty #' #' @rdname IsMatrixEmpty #' @export IsMatrixEmpty #' #' @concept utils #' #' @examples #' IsMatrixEmpty(new("matrix")) #' IsMatrixEmpty(matrix()) #' IsMatrixEmpty(matrix(1:3)) #' IsMatrixEmpty <- function(x) { UseMethod(generic = 'IsMatrixEmpty', object = x) } #' Split and Join Layers Together #' #' @param object An object #' @template param-dots-method #' #' @return \code{object} with the layers specified joined #' #' @rdname SplitLayers #' @export JoinLayers #' #' @concept assay5 #' JoinLayers <- function(object, ...) { UseMethod(generic = 'JoinLayers', object = object) } #' Get and set JackStraw information #' #' @template param-dots-method #' @param object An object #' #' @return \code{JS}: either a \code{\link{JackStrawData}} object or the #' specified jackstraw data #' #' @rdname JS #' @export JS #' #' @concept jackstraw #' JS <- function(object, ...) { UseMethod(generic = 'JS', object = object) } #' @param value JackStraw information #' #' @return \code{JS<-}: \code{object} with the update jackstraw information #' #' @rdname JS #' @export JS<- #' "JS<-" <- function(object, ..., value) { UseMethod(generic = 'JS<-', object = object) } #' Get and set object keys #' #' @template param-dots-method #' @param object An object #' #' @return \code{Key}: the object key #' #' @rdname Key #' @export Key #' #' @concept data-access #' Key <- function(object, ...) { UseMethod(generic = 'Key', object = object) } #' @return \code{Keys}: a named vector of keys of sub-objects #' #' @rdname Key #' @export #' Keys <- function(object, ...) { UseMethod(generic = 'Keys', object = object) } #' @param value Key value #' #' @return \code{Key<-}: \code{object} with an updated key #' #' @rdname Key #' @export Key<- #' #' @concept data-access #' "Key<-" <- function(object, ..., value) { UseMethod(generic = 'Key<-', object = object) } #' Query and Manipulate Assay Layers #' #' @template param-dots-method #' @param object An object #' @param layer Name of layer to fetch or set #' @param slot \Sexpr[stage=build,results=rd]{lifecycle::badge("deprecated")} #' #' @return \code{LayerData}: the layer data for \code{layer} from \code{object} #' #' @rdname Layers #' @export LayerData #' LayerData <- function(object, layer, ...) { UseMethod(generic = 'LayerData', object = object) } #' @param value New two-dimensional data to be added as a layer #' #' @return \code{Layer<-}: \code{object} with \code{value} added as a layer #' named \code{layer} #' #' @rdname Layers #' @export LayerData<- #' "LayerData<-" <- function(object, layer, ..., value) { UseMethod(generic = 'LayerData<-', object = object) } #' @return \code{Layers}: the names of the layers present in \code{object} #' #' @rdname Layers #' @export Layers #' #' @concept data-access #' Layers <- function(object, ...) { UseMethod(generic = 'Layers', object = object) } #' Get and set feature loadings #' #' @template param-dots-method #' @param object An object #' #' @return \code{Loadings}: the feature loadings for \code{object} #' #' @rdname Loadings #' @export Loadings #' #' @concept data-access #' Loadings <- function(object, ...) { UseMethod(generic = 'Loadings', object = object) } #' @param value Feature loadings to add #' #' @return \code{Loadings<-}: \code{object} with the updated loadings #' #' @rdname Loadings #' @export Loadings<- #' "Loadings<-" <- function(object, ..., value) { UseMethod(generic = 'Loadings<-', object = object) } #' Match Cells #' #' @param new A vector of new cells #' @param orig A vector of existing cells #' @param ordered Sort the result to the same order as \code{orig} #' #' @return A numeric vector with new cells in order of the original cells; if #' no match can be found, returns \code{NULL} #' #' @keywords internal #' #' @export #' #' @concept utils #' MatchCells <- function(new, orig, ordered = FALSE) { if (!is.character(x = orig)) { stop("'orig' must be a character vector") } UseMethod(generic = 'MatchCells', object = new) } #' Get and set miscellaneous data #' #' @param object An object #' @param ... Arguments passed to other methods #' #' @return Miscellaneous data #' #' @rdname Misc #' @export Misc #' #' @concept data-access #' Misc <- function(object, ...) { UseMethod(generic = 'Misc', object = object) } #' @param value Data to add #' #' @return An object with miscellaneous data added #' #' @rdname Misc #' @export Misc<- #' "Misc<-" <- function(object, ..., value) { UseMethod(generic = 'Misc<-', object = object) } #' @return \code{Molecules}: The names of all molecule sets present within #' \code{object} #' #' @rdname Boundaries #' @export #' Molecules <- function(object, ...) { UseMethod(generic = 'Molecules', object = object) } #' Overlay \code{Spatial} Objects Over One Another #' #' Create an overlay of some query spatial object (\code{x}) against some #' target object (\code{y}). Basically, find all components of a query that #' fall within the bounds of a target spatial region #' #' @template param-dots-ignored #' @param x Query \code{Spatial} object #' @param y Target \code{Spatial} object #' @param invert Invert the overlay and return only the components of \code{x} #' that fall \emph{outside} the bounds of \code{y} #' #' @return \code{x} with only the components that fall within the #' bounds of \code{y} #' #' @templateVar pkg sf #' @template note-reqdpkg #' #' @export #' #' @concept spatial #' setGeneric( name = 'Overlay', def = function(x, y, invert = FALSE, ...) { standardGeneric(f = 'Overlay') }, signature = c('x', 'y') ) #' Get and set project information #' #' @template param-dots-method #' @param object An object #' #' @return Project information #' #' @rdname Project #' @export Project #' #' @concept seurat #' Project <- function(object, ...) { UseMethod(generic = 'Project', object = object) } #' @param value Project information to set #' #' @return An object with project information added #' #' @rdname Project #' @export Project<- #' "Project<-" <- function(object, ..., value) { UseMethod(generic = 'Project<-', object = object) } #' Get the spot radius from an image #' #' @param object An image object #' #' @return The radius size #' #' @rdname Radius #' @export Radius #' #' @concept spatialimage #' Radius <- function(object) { UseMethod(generic = 'Radius', object = object) } #' Rename cells #' #' Change the cell names in all the different parts of an object. Can be useful #' before combining multiple objects. #' #' @template param-dots-method #' @param object An object #' #' @return An object with new cell names #' #' @rdname RenameCells #' @export RenameCells #' #' @concept seurat #' RenameCells <- function(object, ...) { UseMethod(generic = 'RenameCells', object = object) } #' @return \code{RenameIdents}: An object with selected identity classes renamed #' #' @rdname Idents #' @export RenameIdents #' @aliases RenameIdent #' #' @examples #' # Rename cell identity classes #' # Can provide an arbitrary amount of idents to rename #' levels(pbmc_small) #' pbmc_small <- RenameIdents(pbmc_small, '0' = 'A', '2' = 'C') #' levels(pbmc_small) #' RenameIdents <- function(object, ...) { UseMethod(generic = 'RenameIdents', object = object) } #' @param var Feature or variable to order on #' #' @return \code{ReorderIdent}: An object with #' #' @rdname Idents #' @export ReorderIdent #' @aliases ReorderIdent #' #' @examples #' \dontrun{ #' head(Idents(pbmc_small)) #' pbmc_small <- ReorderIdent(pbmc_small, var = 'PC_1') #' head(Idents(pbmc_small)) #' } #' ReorderIdent <- function(object, var, ...) { UseMethod(generic = 'ReorderIdent', object = object) } #' S4/List Conversion #' #' Convert S4 objects to lists and vice versa. Useful for declassing an S4 #' object while keeping track of it's class using attributes (see section #' \strong{S4 Class Definition Attributes} below for more details). Both #' \code{ListToS4} and \code{S4ToList} are recursive functions, affecting #' all lists/S4 objects contained as sub-lists/sub-objects #' #' @param object An S4 object #' @param x A list with an S4 class definition #' (\dQuote{\code{classDef}}) attribute #' #' @return \code{S4ToList}: A list with an S4 class definition attribute #' #' @section S4 Class Definition Attributes: #' S4 classes are scoped to the package and class name. In order to properly #' track which class a list is generated from in order to build a new one, #' these function use an \code{\link[base:attr]{attribute}} to denote the #' class name and package of origin. This attribute is stored as 1-length #' character vector named \dQuote{\code{classDef}} and takes the form #' of \dQuote{\code{package:class}} #' #' @name s4list #' @rdname s4list #' #' @keywords internal #' #' @export #' #' @concept utils #' @family s4list #' #' @examples #' # Turn an S4 object into a list #' pbmc.list <- S4ToList(pbmc_small) #' class(pbmc.list) #' attributes(pbmc.list) #' #' str(pbmc.list$reductions) #' S4ToList <- function(object) { if (!(isS4(object) || is_bare_list(x = object))) { return(object) } UseMethod(generic = 'S4ToList', object = object) } #' @param new.data New assay data to add #' #' @return \code{SetAssayData}: \code{object} with the assay data set #' #' @rdname AssayData #' @export SetAssayData #' #' @order 2 #' SetAssayData <- function(object, layer, new.data, slot = deprecated(), ...) { UseMethod(generic = 'SetAssayData', object = object) } #' @return \code{SetIdent}: An object with new identity classes set #' #' @rdname Idents #' @export SetIdent #' #' @examples #' # Set cell identity classes using SetIdent #' cells.use <- WhichCells(pbmc_small, idents = '1') #' pbmc_small <- SetIdent(pbmc_small, cells = cells.use, value = 'B') #' SetIdent <- function(object, ...) { UseMethod(generic = 'SetIdent', object = object) } #' Simplify Geometry #' #' @param coords ... #' #' @return A simplified version of \code{coords} #' #' @export #' #' @concept spatial #' Simplify <- function(coords, tol, topologyPreserve = TRUE) { UseMethod(generic = 'Simplify', object = coords) } #' @return \code{SpatiallyVariableFeatures}: a character vector of the spatially #' variable features #' #' @rdname VariableFeatures #' @export SpatiallyVariableFeatures #' #' @order 5 #' SpatiallyVariableFeatures <- function(object, method, ...) { UseMethod(generic = 'SpatiallyVariableFeatures', object = object) } # @rdname SplitLayers # @export SplitLayers # # @order 1 # SplitLayers <- function(object, ...) { UseMethod(generic = 'SplitLayers', object = object) } #' @return \code{StashIdent}: An object with the identities stashed #' #' @rdname Idents #' @export StashIdent #' #' @examples #' head(pbmc_small[[]]) #' pbmc_small <- StashIdent(pbmc_small, save.name = 'idents') #' head(pbmc_small[[]]) #' StashIdent <- function(object, save.name, ...) { UseMethod(generic = 'StashIdent', object = object) } #' Get the standard deviations for an object #' #' @template param-dots-method #' @param object An object #' #' @return The standard deviations #' #' @rdname Stdev #' @export Stdev #' #' @concept data-access #' Stdev <- function(object, ...) { UseMethod(generic = 'Stdev', object = object) } #' Stitch Matrices Together #' #' @template param-dots-method #' @param x A matrix #' @param y One or more matrices of the same class or coercible to the #' same class as \code{x} #' @param rowmap,colmap \code{\link{LogMap}s} describing the row and cell #' membership of each matrix; the \code{LogMap} entries are assumed to be in #' the order of \code{c(x, y)} #' #' @return A single matrix of type \code{class(x)} consisting of all values #' in component matrices #' #' @export #' #' @concept utils #' StitchMatrix <- function(x, y, rowmap, colmap, ...) { if (!inherits(x = rowmap, what = 'LogMap')) { abort(message = "'rowmap' must be a 'LogMap'") } else if (!inherits(x = colmap, what = 'LogMap')) { abort(message = "'colmap' must be a 'LogMap'") } UseMethod(generic = 'StitchMatrix', object = x) } #' @return \code{SVFInfo}: a data frame with the spatially variable features #' #' @rdname VariableFeatures #' @export SVFInfo #' #' @order 4 #' SVFInfo <- function(object, method, status, ...) { UseMethod(generic = 'SVFInfo', object = object) } #' Get the offset angle #' #' @param object An object #' #' @rdname Theta #' @export #' #' @concept spatial #' Theta <- function(object) { UseMethod(generic = 'Theta', object = object) } #' Get and Set Additional Tool Data #' #' Use \code{Tool} to get tool data. If no additional arguments are provided, #' will return a vector with the names of tools in the object. #' #' @template param-dots-method #' @param object An object #' #' @return If no additional arguments, returns the names of the tools in the #' object; otherwise returns the data placed by the tool requested #' #'@note For developers: set tool data using \code{Tool<-}. \code{Tool<-} will #'automatically set the name of the tool to the function that called #'\code{Tool<-}, so each function gets one entry in the tools list and cannot #'overwrite another function's entry. The automatic naming will also remove any #'method identifiers (eg. \code{RunPCA.Seurat} will become \code{RunPCA}); #'please plan accordingly #' #' @rdname Tool #' @export Tool #' #' @aliases Tools #' #' @concept data-access #' #' @examples #' # Example function that adds unstructured data to tools #' MyTool <- function(object) { #' sample.tool.output <- matrix(rnorm(n = 16), nrow = 4) #' # Note: `Tool<-` must be called from within a function #' # and the name of the tool will be generated from the function name #' Tool(object) <- sample.tool.output #' return(object) #' } #' #' # Run our tool #' set.seed(42L) #' pbmc_small <- MyTool(pbmc_small) #' #' # Get a list of tools run #' Tool(pbmc_small) #' #' # Access specific tool data #' Tool(pbmc_small, slot = "MyTool") #' Tool <- function(object, ...) { UseMethod(generic = 'Tool', object = object) } #' @param value Information to be added to tool list #' #' @rdname Tool #' @export Tool<- #' "Tool<-" <- function(object, ..., value) { UseMethod(generic = 'Tool<-', object = object) } #' @return \code{VariableFeatures}: a vector of the variable features #' #' @rdname VariableFeatures #' @export VariableFeatures #' #' @order 2 #' VariableFeatures <- function(object, method = NULL, ...) { UseMethod(generic = 'VariableFeatures', object = object) } #' @param value A character vector of variable features #' #' @order 3 #' #' @rdname VariableFeatures #' @export VariableFeatures<- #' "VariableFeatures<-" <- function(object, ..., value) { UseMethod(generic = 'VariableFeatures<-', object = object) } #' Get Version Information #' #' @template param-dots-method #' @param object An object #' #' @rdname Version #' @export Version #' #' @concept data-access #' #' @examples #' Version(pbmc_small) #' Version <- function(object, ...) { UseMethod(generic = "Version", object = object) } #' Identify cells matching certain criteria #' #' Returns a list of cells that match a particular set of criteria such as #' identity class, high/low values for particular PCs, etc. #' #' @template param-dots-method #' @param object An object #' #' @return A vector of cell names #' #' @rdname WhichCells #' @export WhichCells #' #' @concept data-access #' #' @seealso \code{\link{FetchData}} #' #' @examples #' WhichCells(pbmc_small, idents = 2) #' WhichCells(pbmc_small, expression = MS4A1 > 3) #' levels(pbmc_small) #' WhichCells(pbmc_small, idents = c(1, 2), invert = TRUE) #' WhichCells <- function(object, ...) { UseMethod(generic = 'WhichCells', object = object) } SeuratObject/R/data.R0000644000176200001440000000207514473173564014123 0ustar liggesusers#' A small example version of the PBMC dataset #' #' A subsetted version of 10X Genomics' 3k PBMC dataset #' #' @format A Seurat object with the following slots filled #' \describe{ #' \item{assays}{ #' \itemize{Currently only contains one assay ("RNA" - scRNA-seq expression data) #' \item{counts - Raw expression data} #' \item{data - Normalized expression data} #' \item{scale.data - Scaled expression data} #' \item{var.features - names of the current features selected as variable} #' \item{meta.features - Assay level metadata such as mean and variance} #' }} #' \item{meta.data}{Cell level metadata} #' \item{active.assay}{Current default assay} #' \item{active.ident}{Current default idents} #' \item{graphs}{Neighbor graphs computed, currently stores the SNN} #' \item{reductions}{Dimensional reductions: currently PCA and tSNE} #' \item{version}{Seurat version used to create the object} #' \item{commands}{Command history} #' } #' @source \url{https://support.10xgenomics.com/single-cell-gene-expression/datasets/1.1.0/pbmc3k} #' "pbmc_small" SeuratObject/R/sparse.R0000644000176200001440000000735714520004144014473 0ustar liggesusers#' @include zzz.R #' @include generics.R #' @importClassesFrom spam spam #' @importClassesFrom Matrix CsparseMatrix RsparseMatrix #' NULL #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' Identify Sparse Slots #' #' @param x A sparse matrix #' @param type ... #' #' @return ... #' #' @keywords internal #' #' @export #' #' @family sparse #' .SparseSlots <- function(x, type = c('pointers', 'indices', 'entries')) { UseMethod(generic = '.SparseSlots', object = x) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Functions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' Is a Matrix Sparse #' #' @param x A matrix #' #' @return ... #' #' @keywords internal #' #' @export #' #' @family sparse #' #' @examples #' IsSparse(matrix()) #' IsSparse(LayerData(pbmc_small, "counts")) #' IsSparse <- function(x) { if (!isS4(x)) { return(FALSE) } classkey <- unlist(x = strsplit( x = ClassKey(class = class(x = x)), split = ':' )) cls <- classkey[[2L]] pkg <- classkey[[1L]] sparse <- cls %in% sparse.classes[[pkg]] if (!sparse) { sparse <- any(sparse.classes[[pkg]] %in% .Contains(object = x)) } return(sparse) } #' Register Sparse Matrix Classes #' #' @inheritParams ClassKey #' #' @return Invisibly returns \code{NULL} #' #' @keywords internal #' #' @export #' #' @family sparse #' RegisterSparseMatrix <- function(class, package = NULL) { classkey <- unlist(x = strsplit( x = ClassKey(class = class, package = package), split = ':' )) sparse.classes[[classkey[[1L]]]] <- unique(c( sparse.classes[[classkey[[1L]]]], classkey[[2L]] )) return(invisible(x = NULL)) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for Seurat-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' @method .MARGIN CsparseMatrix #' @export #' .MARGIN.CsparseMatrix <- function(x, ...) { return(2L) } #' @method .MARGIN RsparseMatrix #' @export #' .MARGIN.RsparseMatrix <- function(x, ...) { return(1L) } #' @method .MARGIN spam #' @export #' .MARGIN.spam <- .MARGIN.RsparseMatrix #' @rdname dot-SparseSlots #' @method .SparseSlots CsparseMatrix #' @export #' .SparseSlots.CsparseMatrix <- function( x, type = c('pointers', 'entries', 'indices') ) { type <- arg_match(arg = type) return(switch( EXPR = type, 'pointers' = 'p', 'indices' = 'i', 'entries' = 'x' )) } #' @rdname dot-SparseSlots #' @method .SparseSlots RsparseMatrix #' @export #' .SparseSlots.RsparseMatrix <- function( x, type = c('pointers', 'indices', 'entries') ) { type <- arg_match(arg = type) return(switch( EXPR = type, 'pointers' = 'p', 'indices' = 'j', 'entries' = 'x' )) } #' @rdname dot-SparseSlots #' @method .SparseSlots spam #' @export #' .SparseSlots.spam <- function(x, type = c('pointers', 'indices', 'entries')) { check_installed(pkg = 'spam') type <- arg_match(arg = type) return(switch( EXPR = type, 'pointers' = 'rowpointers', 'indices' = 'colindices', 'entries' = 'entries' )) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for R-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Internal #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # S4 Methods #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% SeuratObject/R/RcppExports.R0000644000176200001440000000066714473174305015502 0ustar liggesusers# Generated by using Rcpp::compileAttributes() -> do not edit by hand # Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 GraphToNeighborHelper <- function(mat) { .Call('_SeuratObject_GraphToNeighborHelper', PACKAGE = 'SeuratObject', mat) } RowMergeMatricesList <- function(mat_list, mat_rownames, all_rownames) { .Call('_SeuratObject_RowMergeMatricesList', PACKAGE = 'SeuratObject', mat_list, mat_rownames, all_rownames) } SeuratObject/R/command.R0000644000176200001440000002124714520004144014606 0ustar liggesusers#' @include zzz.R #' @include generics.R #' @importFrom methods new slot slot<- #' NULL #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Class definitions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' The \code{SeuratCommand} Class #' #' The \code{SeuratCommand} is used for logging commands that are run #' on a \code{Seurat} object; it stores parameters and timestamps #' #' @slot name Command name #' @slot time.stamp Timestamp of when command was tun #' @slot assay.used Optional name of assay used to generate #' \code{SeuratCommand} object #' @slot call.string String of the command call #' @slot params List of parameters used in the command call #' #' @name SeuratCommand-class #' @rdname SeuratCommand-class #' @exportClass SeuratCommand #' #' @family command #' #' @aliases SeuratCommand #' setClass( Class = 'SeuratCommand', slots = c( name = 'character', time.stamp = 'POSIXct', assay.used = 'OptionalCharacter', call.string = 'character', params = 'ANY' ) ) #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Functions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' Log a command #' #' Logs command run, storing the name, timestamp, and argument list. Stores in #' the Seurat object #' #' @param object Name of Seurat object #' @param return.command Return a \code{\link{SeuratCommand}} object instead #' #' @return If \code{return.command}, returns a \code{\link{SeuratCommand}} #' object; otherwise, returns the Seurat object with command stored #' #' @export #' #' @family command #' #' @seealso \code{\link{Command}} #' LogSeuratCommand <- function(object, return.command = FALSE) { time.stamp <- Sys.time() object <- UpdateSlots(object = object) #capture function name which.frame <- sys.nframe() - 1 if (which.frame < 1) { stop("'LogSeuratCommand' cannot be called at the top level", call. = FALSE) } if (as.character(x = sys.calls()[[1]])[1] == "do.call") { call.string <- deparse(expr = sys.calls()[[1]]) command.name <- as.character(x = sys.calls()[[1]])[2] } else { command.name <- as.character(x = deparse(expr = sys.calls()[[which.frame]])) command.name <- gsub( pattern = "\\.Seurat", replacement = "", x = command.name ) call.string <- command.name command.name <- ExtractField( string = command.name, field = 1, delim = "\\(" ) } #capture function arguments argnames <- names(x = formals(fun = sys.function(which = sys.parent(n = 1)))) argnames <- grep( pattern = "object", x = argnames, invert = TRUE, value = TRUE ) argnames <- grep( pattern = "anchorset", x = argnames, invert = TRUE, value = TRUE ) argnames <- grep( pattern = "\\.\\.\\.", x = argnames, invert = TRUE, value = TRUE ) params <- list() p.env <- parent.frame(n = 1) argnames <- intersect(x = argnames, y = ls(name = p.env)) # fill in params list for (arg in argnames) { param_value <- get(x = arg, envir = p.env) if (inherits(x = param_value, what = 'Seurat')) { next } #TODO Institute some check of object size? params[[arg]] <- param_value } # check if function works on the Assay and/or the DimReduc Level assay <- params[["assay"]] reduction <- params[["reduction"]] # Get assay used for command cmd.assay <- assay %||% (reduction %iff% if (inherits(x = reduction, what = 'DimReduc')) { DefaultAssay(object = reduction) } else if (reduction %in% Reductions(object = object)) { DefaultAssay(object = object[[reduction]]) }) if (inherits(x = reduction, what = 'DimReduc')) { reduction <- 'DimReduc' } # rename function name to include Assay/DimReduc info if (length(x = assay) == 1) { command.name <- paste(command.name, assay, reduction, sep = '.') } command.name <- sub( pattern = "[\\.]+$", replacement = "", x = command.name, perl = TRUE ) command.name <- sub(pattern = "\\.\\.", replacement = "\\.", x = command.name, perl = TRUE) # store results seurat.command <- new( Class = 'SeuratCommand', name = command.name, params = params, time.stamp = time.stamp, call.string = call.string, assay.used = cmd.assay ) if (isTRUE(x = return.command)) { return(seurat.command) } object[[command.name]] <- seurat.command return(object) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for Seurat-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' @rdname DefaultAssay #' @export #' @method DefaultAssay SeuratCommand #' DefaultAssay.SeuratCommand <- function(object, ...) { object <- UpdateSlots(object = object) return(slot(object = object, name = 'assay.used')) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for R-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' @inherit .DollarNames.Seurat title #' #' @description Autocompletion for \code{$} access on a #' \code{\link{SeuratCommand}} object #' #' @inheritParams utils::.DollarNames #' @param x A \code{\link{SeuratCommand}} object #' #' @return The parameter name matches for \code{pattern} #' #' @importFrom utils .DollarNames #' #' @method .DollarNames SeuratCommand #' @export #' #' @family command #' ".DollarNames.SeuratCommand" <- function(x, pattern = '') { return(.DollarNames(x = slot(object = x, name = "params"), pattern = pattern)) } #' Command Log Parameter Access #' #' Pull parameter values from a \code{\link{SeuratCommand}} object #' #' @inheritParams .DollarNames.SeuratCommand #' @param i A parameter name #' #' @return The value for parameter \code{i} #' #' @method $ SeuratCommand #' @export #' #' @family command #' #' @examples #' cmd <- pbmc_small[["NormalizeData.RNA"]] #' cmd$normalization.method #' "$.SeuratCommand" <- function(x, i) { params <- slot(object = x, name = "params") return(params[[i]]) } #' Command Log Data Access #' #' Access data from a \code{SeuratCommand} object #' #' @inheritParams .DollarNames.SeuratCommand #' @param i The name of a command log slot #' @template param-dots-ignored #' #' @return \code{[}: Slot \code{i} from \code{x} #' #' @method [ SeuratCommand #' @export #' #' @family command #' #' @examples #' cmd <- pbmc_small[["NormalizeData.RNA"]] #' cmd["call.string"] #' "[.SeuratCommand" <- function(x, i, ...) { i <- arg_match(arg = i, values = slotNames(x = x)) return(slot(object = x, name = i)) } #' Coerce a \code{SeuratCommand} to a list #' #' @inheritParams .DollarNames.SeuratCommand #' @param complete Include slots besides just parameters #' (eg. call string, name, timestamp) #' @template param-dots-ignored #' #' @return A list with the parameters and, if \code{complete = TRUE}, #' the call string, name, and timestamp #' #' @method as.list SeuratCommand #' @export #' #' @family command #' #' @examples #' cmd <- pbmc_small[["NormalizeData.RNA"]] #' as.list(cmd) #' as.list(cmd, complete = TRUE) #' as.list.SeuratCommand <- function(x, complete = FALSE, ...) { CheckDots(...) cmd <- slot(object = x, name = 'params') if (isTRUE(x = complete)) { cmd <- append( x = cmd, values = sapply( X = setdiff(x = slotNames(x = x), y = 'params'), FUN = slot, object = x, simplify = FALSE, USE.NAMES = TRUE ), after = 0 ) } for (i in seq_along(along.with = cmd)) { if (is.character(x = cmd[[i]])) { cmd[[i]] <- paste(trimws(x = cmd[[i]]), collapse = ' ') } } return(cmd) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # S4 methods #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' Command Log Overview #' #' Overview of a \code{\link{SeuratCommand}} object #' #' @template return-show #' #' @keywords internal #' #' @concept command #' #' @examples #' cmd <- pbmc_small[["NormalizeData.RNA"]] #' cmd #' setMethod( f = 'show', signature = 'SeuratCommand', definition = function(object) { params <- slot(object = object, name = "params") params <- params[sapply(X = params, FUN = class) != "function"] cat( "Command: ", slot(object = object, name = "call.string"), '\n', "Time: ", as.character(slot(object = object, name = "time.stamp")), '\n', sep = "" ) for (p in seq_len(length.out = length(x = params))) { cat( names(params[p]), ":", params[[p]], "\n" ) } } ) #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Internal #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% SeuratObject/R/spatial.R0000644000176200001440000002636014520004144014626 0ustar liggesusers#' @include zzz.R #' @include generics.R #' @importFrom methods setClass slot slot<- new #' NULL #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Class definitions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' The SpatialImage class #' #' The \code{SpatialImage} class is a virtual class representing spatial #' information for Seurat. All spatial image information must inherit from this #' class for use with \code{Seurat} objects #' #' @slot assay Name of assay to associate image data with; will give this image #' priority for visualization when the assay is set as the active/default assay #' in a \code{Seurat} object #' @template slot-key #' #' @name SpatialImage-class #' @rdname SpatialImage-class #' @exportClass SpatialImage #' #' @seealso \code{\link{SpatialImage-methods}} for a list of required and #' provided methods #' #' @aliases SpatialImage #' setClass( Class = 'SpatialImage', contains = 'VIRTUAL', slots = list( 'assay' = 'character', 'key' = 'character' ) ) #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Functions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for Seurat-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' \code{SpatialImage} methods #' #' Methods defined on the \code{\link{SpatialImage}} class. Some of these #' methods must be overridden in order to ensure proper functionality of the #' derived classes (see \strong{Required methods} below). Other methods are #' designed to work across all \code{SpatialImage}-derived subclasses, and #' should only be overridden if necessary #' #' @param x,object A \code{SpatialImage}-derived object #' @param ... Arguments passed to other methods #' @param value Depends on the method: #' \describe{ #' \item{\code{DefaultAssay<-}}{Assay that the image should be #' associated with} #' \item{\code{Key<-}}{New key for the image} #' } #' @inheritParams RenameCells #' #' @section Provided methods: #' These methods are defined on the \code{SpatialImage} object and should not #' be overridden without careful thought #' \itemize{ #' \item \code{\link{DefaultAssay}} and \code{\link{DefaultAssay<-}} #' \item \code{\link{Key}} and \code{\link{Key<-}} #' \item \code{\link{GetImage}}; this method \emph{can} be overridden to #' provide image data, normally returns empty image data. If overridden, #' should default to returning a \code{\link[grid]{grob}} object #' \item \code{\link{IsGlobal}} #' \item \code{\link{Radius}}; this method \emph{can} be overridden to #' provide a spot radius for image objects #' \item \code{\link[base:Extract]{[}}; this method \emph{can} be overridden #' to change default subset behavior, normally returns #' \code{subset(x = x, cells = i)}. If overridden, should only accept \code{i} #' } #' #' @section Required methods: #' All subclasses of the \code{SpatialImage} class must define the following #' methods; simply relying on the \code{SpatialImage} method will result in #' errors. For required parameters and their values, see the \code{Usage} and #' \code{Arguments} sections #' \describe{ #' \item{\code{\link{Cells}}}{ #' Return the cell/spot barcodes associated with each position #' } #' \item{\code{\link{dim}}}{ #' Return the dimensions of the image for plotting in \code{(Y, X)} format #' } #' \item{\code{\link{GetTissueCoordinates}}}{ #' Return tissue coordinates; by default, must return a two-column #' \code{data.frame} with x-coordinates in the first column and #' y-coordinates in the second #' } #' \item{\code{\link{Radius}}}{ #' Return the spot radius; returns \code{NULL} by default for use with #' non-spot image technologies #' } #' \item{\code{\link{RenameCells}}}{ #' Rename the cell/spot barcodes for this image #' } #' \item{\code{\link{subset}}}{ #' Subset the image data by cells/spots #' } #' } #' These methods are used throughout Seurat, so defining them and setting the #' proper defaults will allow subclasses of \code{SpatialImage} to work #' seamlessly #' #' @name SpatialImage-methods #' @rdname SpatialImage-methods #' #' @concept spatialimage #' NULL #' @describeIn SpatialImage-methods Get the cell names from an image #' (\strong{[Override]}) #' #' @return \strong{[Override]} \code{Cells}: should return cell names #' #' @method Cells SpatialImage #' @export #' Cells.SpatialImage <- function(x, ...) { stop( "'Cells' must be implemented for all subclasses of 'SpatialImage'", call. = FALSE ) } #' @describeIn SpatialImage-methods Get the associated assay of a #' \code{SpatialImage}-derived object #' #' @return \code{DefaultAssay}: The associated assay of a #' \code{SpatialImage}-derived object #' #' @method DefaultAssay SpatialImage #' @export #' #' @seealso \code{\link{DefaultAssay}} #' DefaultAssay.SpatialImage <- function(object, ...) { CheckDots(...) return(slot(object = object, name = 'assay')) } #' @describeIn SpatialImage-methods Set the associated assay of a #' \code{SpatialImage}-derived object #' #' @return \code{DefaultAssay<-}: \code{object} with the associated assay #' updated #' #' @method DefaultAssay<- SpatialImage #' @export #' "DefaultAssay<-.SpatialImage" <- function(object, ..., value) { CheckDots(...) slot(object = object, name = 'assay') <- value return(object) } #' @describeIn SpatialImage-methods Get the image data from a #' \code{SpatialImage}-derived object #' #' @inheritParams GetImage #' #' @return \strong{[Override]} \code{GetImage}: The image data from a #' \code{SpatialImage}-derived object #' #' @method GetImage SpatialImage #' @export #' #' @seealso \code{\link{GetImage}} #' GetImage.SpatialImage <- function( object, mode = c('grob', 'raster', 'plotly', 'raw'), ... ) { return(NullImage(mode = mode)) } #' @describeIn SpatialImage-methods Get tissue coordinates for a #' \code{SpatialImage}-derived object (\strong{[Override]}) #' #' @return \strong{[Override]} \code{GetTissueCoordinates}: ... #' #' @method GetTissueCoordinates SpatialImage #' @export #' #' @seealso \code{\link{GetTissueCoordinates}} #' GetTissueCoordinates.SpatialImage <- function(object, ...) { stop( "'GetTissueCoordinates' must be implemented for all subclasses of 'SpatialImage'", call. = FALSE ) } #' @describeIn SpatialImage-methods Globality test for #' \code{SpatialImage}-derived object #' #' @return \code{IsGlobal}: returns \code{TRUE} as images are, by default, #' global #' #' @method IsGlobal SpatialImage #' @export #' #' @seealso \code{\link{IsGlobal}} #' IsGlobal.SpatialImage <- function(object, ...) { return(TRUE) } #' @describeIn SpatialImage-methods Get the key for a #' \code{SpatialImage}-derived object #' #' @return \code{Key}: The key for a \code{SpatialImage}-derived object #' #' @method Key SpatialImage #' @export #' #' @seealso \code{\link{Key}} #' Key.SpatialImage <- function(object, ...) { CheckDots(...) # object <- UpdateSlots(object = object) return(slot(object = object, name = 'key')) } #' @describeIn SpatialImage-methods Set the key for a #' \code{SpatialImage}-derived object #' #' @return \code{Key<-}: \code{object} with the key set to \code{value} #' #' @method Key<- SpatialImage #' @export #' "Key<-.SpatialImage" <- function(object, ..., value) { CheckDots(...) object <- UpdateSlots(object = object) value <- UpdateKey(key = value) slot(object = object, name = 'key') <- value return(object) } #' @describeIn SpatialImage-methods Get the spot radius size #' #' @return \code{Radius}: The spot radius size; by default, returns \code{NULL} #' #' @method Radius SpatialImage #' @export #' Radius.SpatialImage <- function(object) { return(NULL) } #' @describeIn SpatialImage-methods Rename cells in a #' \code{SpatialImage}-derived object (\strong{[Override]}) #' #' @return \strong{[Override]} \code{RenameCells}: \code{object} with the new #' cell names #' #' @method RenameCells SpatialImage #' @export #' #' @seealso \code{\link{RenameCells}} #' RenameCells.SpatialImage <- function(object, new.names = NULL, ...) { stop( "'RenameCells' must be implemented for all subclasses of 'SpatialImage'", call. = FALSE ) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for R-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' @describeIn SpatialImage-methods Subset a \code{SpatialImage}-derived object #' #' @param i,cells A vector of cells to keep #' #' @return \code{[}, \code{subset}: \code{x}/\code{object} for only the cells #' requested #' #' @method [ SpatialImage #' @export #' "[.SpatialImage" <- function(x, i, ...) { return(subset(x = x, cells = i)) } #' @describeIn SpatialImage-methods Get the plotting dimensions of an image #' (\strong{[Override]}) #' #' @return \strong{[Override]} \code{dim}: The dimensions of the image data in #' (Y, X) format #' #' @method dim SpatialImage #' @export #' dim.SpatialImage <- function(x) { stop( "'dim' must be implemented for all subclasses of 'SpatialImage'", call. = FALSE ) } #' @describeIn SpatialImage-methods Subset a \code{SpatialImage}-derived object #' (\strong{[Override]}) #' #' @method subset SpatialImage #' @export #' subset.SpatialImage <- function(x, cells, ...) { stop("'subset' must be implemented for all subclasses of 'SpatialImage'") } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # S4 methods #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' @describeIn SpatialImage-methods Overview of a \code{SpatialImage}-derived #' object #' #' @return \code{show}: Prints summary to \code{\link[base]{stdout}} and #' invisibly returns \code{NULL} #' #' @importFrom methods show #' #' @export #' setMethod( f = 'show', signature = 'SpatialImage', definition = function(object) { object <- UpdateSlots(object = object) cat( "Spatial data from the", class(x = object), "technology for", length(x = Cells(x = object)), "samples\n" ) cat("Associated assay:", DefaultAssay(object = object), "\n") cat("Image key:", Key(object = object), "\n") return(invisible(x = NULL)) } ) #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Internal #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' Return a null image #' #' @inheritParams GetImage #' #' @return Varies by value of \code{mode}: #' \describe{ #' \item{\dQuote{grob}}{a \code{\link[grid]{nullGrob}}} #' \item{\dQuote{raster}}{an empty \code{\link[grDevices:as.raster]{raster}}} #' \item{\dQuote{plotly}}{a list with one named item: \code{value = FALSE}} #' \item{\dQuote{raw}}{returns \code{NULL}} #' } #' #' @importFrom grid nullGrob #' @importFrom grDevices as.raster #' #' @keywords internal #' #' @noRd #' NullImage <- function(mode = c('grob', 'raster', 'plotly', 'raw')) { mode <- mode[1] mode <- match.arg(arg = mode) image <- switch( EXPR = mode, 'grob' = nullGrob(), 'raster' = as.raster(x = new(Class = 'matrix')), 'plotly' = list('visible' = FALSE), 'raw' = NULL, stop("Unknown image mode: ", mode, call. = FALSE) ) return(image) } SeuratObject/R/compliance.R0000644000176200001440000000342714520004144015302 0ustar liggesusers.SetSeuratCompat <- local({ seurat.version <- NULL function(pkgname, pkgpath) { current <- .RoundVersion(current = packageVersion(pkg = pkgname)) if (pkgname == 'Signac') { if (is.null(x = seurat.version)) { seurat.version <<- ifelse( test = paste(current, collapse = '.') >= '1.12.9000', yes = '5.0.0', no = '4.4.0' ) } return(invisible(x = NULL)) } seurat.version <<- paste(current, collapse = '.') if (!is.null(x = seurat.version) && seurat.version < '5.0.0') { options( Seurat.object.assay.brackets = 'v3', Seurat.object.assay.version = 'v3' ) } return(invisible(x = NULL)) } }) .GetSeuratCompat <- local( envir = environment(fun = .SetSeuratCompat), function() { if (is.null(x = seurat.version) && isNamespaceLoaded(name = 'Seurat')) { .SetSeuratCompat() } return(seurat.version %||% '5.0.0') } ) .SeuratCompatMessage <- local( envir = environment(fun = .SetSeuratCompat), function(pkgname, pkgpath) { seurat <- .GetSeuratCompat() if (!is.null(x = seurat) && seurat < '5.0.0') { options( Seurat.object.assay.brackets = 'v3', Seurat.object.assay.version = 'v3' ) version <- paste0('v', substr(x = seurat, start = 1L, stop = 1L)) packageStartupMessage(paste( strwrap(x = paste( pkgname, switch( EXPR = pkgname, Seurat = version, "built for for SeuratObject v4" ), "was just loaded with SeuratObject v5;", "disabling v5 assays and validation routines,", "and ensuring assays work in strict v3/v4 compatibility mode" )), collapse = '\n' )) } return(invisible(x = NULL)) } ) SeuratObject/R/molecules.R0000644000176200001440000002567714520004201015165 0ustar liggesusers#' @include zzz.R #' @include generics.R #' @include keymixin.R #' @importFrom future.apply future_lapply #' @importClassesFrom sp CRS SpatialPoints NULL #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Class definitions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' The Spatial Molecules Class #' #' @slot .Data A list of \code{\link[sp]{SpatialPoints}} objects #' @slot key The key for the \code{Molecules} #' #' @family segmentation #' @templateVar cls Molecules #' @template seealso-methods #' setClass( Class = 'Molecules', contains = c('KeyMixin', 'list') ) #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Functions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for Seurat-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' \code{Molecules} Methods #' #' Methods for \code{\link{Molecules}} objects #' #' @inheritParams Centroids-methods #' @param x,object A \code{\link{Molecules}} object #' @param features A vector of molecule names to keep; if \code{NULL}, defaults #' to all molecules #' #' @name Molecules-methods #' @rdname Molecules-methods #' #' @seealso \code{\link{Molecules-class}} #' #' @family segmentation #' NULL #' @param key A key to set for the molecules #' #' @importFrom sp SpatialPoints #' #' @rdname CreateMolecules #' @method CreateMolecules data.frame #' @export #' CreateMolecules.data.frame <- function(coords, key = '', ...) { idx <- NameIndex(x = coords, names = c('x', 'y', 'gene'), MARGIN = 2L) xy <- idx[c('x', 'y')] coords <- split(x = coords, f = coords[[idx[['gene']]]]) p <- progressor(steps = length(x = coords)) coords <- sapply( X = coords, FUN = function(x) { p() mat <- as.matrix(x = x[, xy]) rownames(x = mat) <- NULL return(SpatialPoints(coords = mat)) }, simplify = FALSE, USE.NAMES = TRUE ) obj <- new( Class = 'Molecules', .Data = coords, key = ifelse(test = nchar(x = key), yes = Key(object = key), no = key) ) validObject(object = obj) return(obj) } #' @rdname CreateMolecules #' @method CreateMolecules Molecules #' @export #' CreateMolecules.Molecules <- function(coords, ...) { return(coords) } #' @rdname CreateMolecules #' @method CreateMolecules NULL #' @export #' CreateMolecules.NULL <- function(coords, ...) { return(NULL) } #' @method Crop Molecules #' @export #' Crop.Molecules <- function( object, x = NULL, y = NULL, coords = c('plot',' tissue'), ... ) { object <- .Crop(object = object, x = x, y = y, coords = coords, ...) for (i in names(x = object)) { if (!nrow(x = slot(object = object[[i]], name = 'coords'))) { object[[i]] <- NULL } } if (!length(x = object)) { return(NULL) } return(object) } #' @template method-features #' #' @rdname Molecules-methods #' @method Features Molecules #' @export #' Features.Molecules <- function(x, ...) { return(names(x = x)) } #' @method FetchData Molecules #' @export #' FetchData.Molecules <- function( object, vars, nmols = NULL, seed = NA_integer_, ... ) { vars <- gsub( pattern = paste0('^', Key(object = object)), replacement = '', x = vars ) coords <- GetTissueCoordinates(object = object, features = vars) if (!is.null(x = nmols)) { if (!is.na(x = seed)) { set.seed(seed = seed) } coords <- lapply( X = unique(x = coords$molecule), FUN = function(m) { df <- coords[coords$molecule == m, , drop = FALSE] if (nrow(x = df) > nmols) { idx <- sample(x = seq_len(length.out = nrow(x = df)), size = nmols) df <- df[idx, , drop = FALSE] } return(df) } ) coords <- do.call(what = 'rbind', args = coords) } return(coords) # return(fortify(model = object, data = vars, ...)) } #' @details \code{GetTissueCoordinates}: Get spatially-resolved #' molecule coordinates #' #' @return \code{GetTissueCoordinates}: A data frame with three columns: #' \itemize{ #' \item \dQuote{\code{x}}: the x-coordinate of a molecule #' \item \dQuote{\code{y}}: the y-coordinate of a molecule #' \item \dQuote{\code{molecule}}: the molecule name #' } #' #' @importFrom sp coordinates #' #' @rdname Molecules-methods #' @method GetTissueCoordinates Molecules #' @export #' GetTissueCoordinates.Molecules <- function(object, features = NULL, ...) { features <- features %||% Features(x = object) coords <- lapply( X = features, FUN = function(f) { fcoords <- object[[f]] if (is.null(x = fcoords)) { return(NULL) } fcoords <- as.data.frame(x = coordinates(obj = fcoords)) rownames(x = fcoords) <- NULL fcoords$molecule <- f return(fcoords) } ) return(do.call(what = 'rbind', args = coords)) } #' @method Simplify Molecules #' @export #' Simplify.Molecules <- function(coords, tol, topologyPreserve = TRUE) { .NotYetImplemented() } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for R-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' @importFrom stats aggregate #' @rdname aggregate #' @method aggregate Molecules #' @export #' aggregate.Molecules <- function(x, by, drop = TRUE, ...) { if (!inherits(x = by, what = 'SpatialPolygons')) { stop( "Aggregation of molecules works only with spatial polygons", call. = FALSE ) } oob <- 'boundless' cells <- unname(obj = names(x = by)) if (isFALSE(x = drop)) { if (oob %in% cells) { oob <- RandomName(length = 7L) warning( "'boundless' already present in cell names, changing to '", oob, "'", call. = FALSE, immediate. = TRUE ) } cells <- c(cells, oob) } idx <- over(x = x, y = by) m <- Matrix( data = 0, nrow = length(x = idx), ncol = length(x = cells), dimnames = list(Features(x = x), cells), sparse = TRUE ) p <- progressor(along = idx) p(message = "Creating expression matrix", class = 'sticky', amount = 0) for (i in seq_along(along.with = idx)) { x <- idx[[i]] f <- names(x = idx)[i] if (isFALSE(x = drop)) { m[f, oob] <- sum(is.na(x = x)) } x <- sort(x = unname(obj = x[!is.na(x = x)])) x <- rle(x = x) m[f, x$values] <- x$lengths p() } return(m) } #' @details \code{subset}: Subset a \code{Molecules} object to certain molecules #' #' @return \code{subset}: \code{x} subsetted to the features specified #' by \code{features} #' #' @rdname Molecules-methods #' @method subset Molecules #' @export #' subset.Molecules <- function(x, features = NULL, ...) { features <- Features(x = x) %iff% features if (is.null(x = features)) { return(x) } else if (length(x = features) == 1L && is.na(x = features)) { return(CreateMolecules(coords = NULL)) } if (is.numeric(x = features)) { features <- names(x = x)[features] features <- features[!is.na(x = features)] } features <- MatchCells(new = Features(x = x), orig = features, ordered = TRUE) if (!length(x = features)) { warning("None of the requested features found", immediate. = TRUE) return(CreateMolecules(coords = NULL)) } x <- x[features] return(as(object = x, Class = 'Molecules')) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Internal #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # S4 methods #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% setMethod( f = 'bbox', signature = 'Molecules', definition = function(obj) { bounds <- lapply(X = obj, FUN = bbox) bounds <- do.call(what = 'cbind', args = bounds) bounds <- apply(X = bounds, MARGIN = 1L, FUN = range) rownames(x = bounds) <- c('min', 'max') return(t(x = bounds)) } ) setMethod( f = 'over', signature = c(x = 'Molecules', y = 'SpatialPolygons'), definition = function(x, y, returnList = FALSE, fn = NULL, ...) { f <- Features(x = x) p <- progressor(steps = length(x = f)) out <- future_lapply( X = seq_along(along.with = f), FUN = function(i) { fi <- f[[i]] p() return(over(x = x[[fi]], y = y, returnList = returnList, fn = fn, ...)) } ) names(x = out) <- f return(out) } ) #' @rdname Overlay #' @export #' setMethod( f = 'Overlay', signature = c(x = 'Molecules', y = 'SpatialPolygons'), definition = function(x, y, invert = FALSE, ...) { idx <- over(x = x, y = y) for (f in names(x = idx)) { select <- idx[[f]] select <- select[!is.na(x = select)] cells <- as.integer(x = names(x = select)) if (isTRUE(x = invert)) { cells <- -cells } x[[f]] <- x[[f]][cells] } for (i in names(x = x)) { if (!nrow(x = slot(object = x[[i]], name = 'coords'))) { x[[i]] <- NULL } } if (!length(x = x)) { return(NULL) } validObject(object = x) return(x) } ) #' @template method-show #' #' @rdname Molecules-methods #' setMethod( f = 'show', signature = c(object = 'Molecules'), definition = function(object) { nmols <- length(x = object) molword <- ifelse(test = nmols == 1L, yes = 'molecule', no = 'molecules') cat("Coordinates for", nmols, molword, "\n") hmols <- min(nmols, 10) cat( "First", hmols, paste0(molword, ':'), paste( strwrap(x = paste( head(x = names(x = object), n = hmols), collapse = ', ' )), collapse = '\n ' ), '\n' ) } ) setValidity( Class = 'Molecules', method = function(object) { if (isFALSE(x = getOption(x = "Seurat.object.validate", default = TRUE))) { warn( message = paste("Not validating", class(x = object)[1L], "objects"), class = 'validationWarning' ) return(TRUE) } else if (!length(x = object)) { return(TRUE) } valid <- NULL # Check names unnamed <- is.null(x = names(x = object)) || length(x = Filter(f = nchar, x = names(x = object))) != length(x = object) if (isTRUE(x = unnamed)) { valid <- c(valid, 'All entries must be named') } # Check SpatialPoints points <- vapply( X = object, FUN = inherits, FUN.VALUE = logical(length = 1L), what = 'SpatialPoints' ) if (!all(points)) { valid <- c(valid, 'All entries must inherit from sp::SpatialPoints') } # Check that coordinates have no rownames rnames <- vapply( X = object, FUN = function(x) { return(is.null(x = rownames(x = slot(object = x, name = 'coords')))) }, FUN.VALUE = logical(length = 1L) ) if (!all(rnames)) { valid <- c(valid, 'All entries must have unnamed coordinates') } return(valid %||% TRUE) } ) SeuratObject/R/dimreduc.R0000644000176200001440000010154214520004144014761 0ustar liggesusers#' @include zzz.R #' @include generics.R #' @include jackstraw.R #' @include keymixin.R #' @importFrom methods new slot slot<- slotNames #' NULL #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Class definitions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' The Dimensional Reduction Class #' #' The DimReduc object stores a dimensionality reduction taken out in Seurat; #' each DimReduc consists of a cell embeddings matrix, a feature loadings #' matrix, and a projected feature loadings matrix. #' #' @slot cell.embeddings Cell embeddings matrix (required) #' @slot feature.loadings Feature loadings matrix (optional) #' @slot feature.loadings.projected Projected feature loadings matrix (optional) #' @slot assay.used Name of assay used to generate \code{DimReduc} object #' @slot global Is this \code{DimReduc} global/persistent? If so, it will not be #' removed when removing its associated assay #' @slot stdev A vector of standard deviations #' @slot jackstraw A \code{\link{JackStrawData-class}} object associated with #' this \code{DimReduc} #' @template slot-misc #' @template slot-key #' #' @exportClass DimReduc #' #' @aliases DimReduc #' #' @family dimreduc #' setClass( Class = 'DimReduc', contains = 'KeyMixin', slots = c( cell.embeddings = 'matrix', feature.loadings = 'matrix', feature.loadings.projected = 'matrix', assay.used = 'character', global = 'logical', stdev = 'numeric', # key = 'character', jackstraw = 'JackStrawData', misc = 'list' ) ) #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Functions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' Create a DimReduc object #' #' @param embeddings A matrix with the cell embeddings #' @param loadings A matrix with the feature loadings #' @param projected A matrix with the projected feature loadings #' @param assay Assay used to calculate this dimensional reduction #' @param stdev Standard deviation (if applicable) for the dimensional reduction #' @param key A character string to facilitate looking up features from a #' specific DimReduc #' @param global Specify this as a global reduction (useful for visualizations) #' @param jackstraw Results from the JackStraw function #' @param misc list for the user to store any additional information associated #' with the dimensional reduction #' #' @return A \code{\link{DimReduc}} object #' #' @aliases SetDimReduction #' #' @export #' #' @family dimreduc #' #' @examples #' data <- GetAssayData(pbmc_small[["RNA"]], slot = "scale.data") #' pcs <- prcomp(x = data) #' pca.dr <- CreateDimReducObject( #' embeddings = pcs$rotation, #' loadings = pcs$x, #' stdev = pcs$sdev, #' key = "PC", #' assay = "RNA" #' ) #' CreateDimReducObject <- function( embeddings = new(Class = 'matrix'), loadings = new(Class = 'matrix'), projected = new(Class = 'matrix'), assay = NULL, stdev = numeric(), key = NULL, global = FALSE, jackstraw = NULL, misc = list() ) { if (is.null(x = assay)) { warn(message = "No assay specified, setting assay as RNA by default.") assay <- 'RNA' } # Try to infer key from column names if (is.null(x = key) && is.null(x = colnames(x = embeddings))) { abort(message = "Please specify a key for the DimReduc object") } else if (is.null(x = key)) { key <- regmatches( x = colnames(x = embeddings), m = regexec(pattern = '^[[:alnum:]]+_', text = colnames(x = embeddings)) ) key <- unique(x = unlist(x = key, use.names = FALSE)) } if (length(x = key) != 1) { abort(message = "Please specify a key for the DimReduc object") } else if (!grepl(pattern = .KeyPattern(), x = key)) { old.key <- key key <- Key(object = key) colnames(x = embeddings) <- gsub( x = colnames(x = embeddings), pattern = old.key, replacement = key ) } # ensure colnames of the embeddings are the key followed by a numeric if (is.null(x = colnames(x = embeddings))) { warn(message = paste0( "No columnames present in cell embeddings, setting to '", key, "1:", ncol(x = embeddings), "'" )) colnames(x = embeddings) <- paste0(key, 1:ncol(x = embeddings)) } else if (!all(grepl(pattern = paste0('^', key, "[[:digit:]]+$"), x = colnames(x = embeddings)))) { digits <- unlist(x = regmatches( x = colnames(x = embeddings), m = regexec(pattern = '[[:digit:]]+$', text = colnames(x = embeddings)) )) if (length(x = digits) != ncol(x = embeddings)) { stop("Please ensure all column names in the embeddings matrix are the key plus a digit representing a dimension number") } colnames(x = embeddings) <- paste0(key, digits) } if (!IsMatrixEmpty(x = loadings)) { if (any(rownames(x = loadings) == '')) { abort(message = "Feature names of loadings matrix cannot be empty") } colnames(x = loadings) <- colnames(x = embeddings) } if (!IsMatrixEmpty(x = projected)) { if (any(rownames(x = loadings) == '')) { abort(message = "Feature names of projected loadings matrix cannot be empty") } colnames(x = projected) <- colnames(x = embeddings) } jackstraw <- jackstraw %||% new(Class = 'JackStrawData') dim.reduc <- new( Class = 'DimReduc', cell.embeddings = embeddings, feature.loadings = loadings, feature.loadings.projected = projected, assay.used = assay, global = global, stdev = stdev, key = key, jackstraw = jackstraw, misc = misc ) return(dim.reduc) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for Seurat-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' @rdname Cells #' @export #' @method Cells DimReduc #' Cells.DimReduc <- function(x, ...) { return(rownames(x = x)) } #' @rdname DefaultAssay #' @export #' @method DefaultAssay DimReduc #' DefaultAssay.DimReduc <- function(object, ...) { CheckDots(...) return(slot(object = object, name = 'assay.used')) } #' @rdname DefaultAssay #' @export #' @method DefaultAssay<- DimReduc #' "DefaultAssay<-.DimReduc" <- function(object, ..., value) { CheckDots(...) slot(object = object, name = 'assay.used') <- value return(object) } #' @method Features DimReduc #' @export #' Features.DimReduc <- function(x, projected = NULL, ...) { projected <- isTRUE(x = projected %||% Projected(object = x)) features <- rownames(x = Loadings(object = x, projected = projected)) if (!length(x = features)) { features <- NULL } return(features) } #' @rdname FetchData #' @export #' @method FetchData DimReduc #' FetchData.DimReduc <- function( object, vars, cells = NULL, slot = c('embeddings', 'loadings', 'projected'), ... ) { slot <- slot[1L] slot <- match.arg(arg = slot) cells <- cells %||% Cells(x = object) if (is.numeric(x = cells)) { cells <- Cells(x = object)[cells] } pattern <- paste0('^(', Key(object = object), ')?[[:digit:]]+$') vars <- grep(pattern = pattern, x = vars, value = TRUE) if (!length(x = 'vars')) { stop("invalid vars") } vars <- gsub(pattern = Key(object = object), replacement = '', x = vars) vars <- as.integer(x = vars) vars <- paste0(Key(object = object), vars) data <- switch( EXPR = slot, 'embeddings' = Embeddings(object = object), Loadings(object = object, projected = slot == 'projected') ) missing <- setdiff(x = vars, y = colnames(x = data)) if (length(x = missing) == length(x = vars)) { stop("Cannot find any of the requested dimensions") } else if (length(x = missing)) { warning( "Cannot find the following dimensions: ", paste0(missing, collapse = ', '), call. = FALSE, immediate. = TRUE ) vars <- setdiff(x = vars, y = missing) } return(as.data.frame(x = data)[cells, vars, drop = FALSE]) } #' @rdname Embeddings #' @export #' @method Embeddings DimReduc #' #' @examples #' # Get the embeddings directly from a DimReduc object #' Embeddings(object = pbmc_small[["pca"]])[1:5, 1:5] #' Embeddings.DimReduc <- function(object, ...) { CheckDots(...) return(slot(object = object, name = 'cell.embeddings')) } #' @method FetchData DimReduc #' @export #' FetchData.DimReduc <- function( object, vars, cells = NULL, # layer = c('embeddings', 'loadings', 'projected'), # layer = 'embeddings', ... ) { layer <- 'embeddings' layer <- arg_match0(arg = layer, values = 'embeddings') cells <- cells %||% Cells(x = object) if (is.numeric(x = cells)) { cells <- Cells(x = object)[cells] } cells <- intersect(x = cells, y = Cells(x = object)) if (!length(x = cells)) { abort(message = "None of the cells requested found in this dimensional reduction") } key <- Key(object = object) ovars <- vars vars <- grep( pattern = paste0('^(', key, ')?[[:digit:]]+$'), x = vars, value = TRUE ) if (!length(x = vars)) { abort(message = "None of the vars provided are valid for reduced dimensions") } else if (length(x = vars) != length(x = ovars)) { warn(message = paste( "The following requested vars are not valid:", paste(setdiff(x = ovars, y = vars), collapse = ', '), )) } vars <- paste0( key, as.integer(x = gsub(pattern = key, replacement = '', x = vars)) ) data <- switch( EXPR = layer, 'embeddings' = Embeddings(object = object), Loadings(object = object, projected = layer == 'projected') ) missing <- setdiff(x = vars, y = colnames(x = data)) if (length(x = missing) == length(x = vars)) { abort(message = "Cannot find any of the requested dimensions") } else if (length(x = missing)) { warn(message = paste( "Cannot find the following dimensions:", paste0(missing, collapse = ', ') )) vars <- setdiff(x = vars, y = missing) } return(as.data.frame(x = data)[cells, vars, drop = FALSE]) } #' @rdname IsGlobal #' @export #' @method IsGlobal DimReduc #' IsGlobal.DimReduc <- function(object, ...) { object <- UpdateSlots(object = object) return(slot(object = object, name = 'global')) } #' @param slot Name of slot to store JackStraw scores to #' Can shorten to 'empirical', 'fake', 'full', or 'overall' #' #' @rdname JS #' @export #' @method JS DimReduc #' JS.DimReduc <- function(object, slot = NULL, ...) { CheckDots(...) jackstraw <- slot(object = object, name = 'jackstraw') if (!is.null(x = slot)) { jackstraw <- JS(object = jackstraw, slot = slot) } return(jackstraw) } #' @rdname JS #' @export #' @method JS<- DimReduc #' "JS<-.DimReduc" <- function(object, slot = NULL, ..., value) { CheckDots(...) if (inherits(x = value, what = 'JackStrawData')) { slot(object = object, name = 'jackstraw') <- value } else if (is.null(x = NULL)) { stop("A slot must be specified") } else { JS(object = JS(object = object), slot = slot) <- value } return(object) } #' @rdname Key #' @export #' @method Key DimReduc #' #' @examples #' # Get a DimReduc key #' Key(object = pbmc_small[["pca"]]) #' Key.DimReduc <- .Key #' @rdname Key #' @export #' @method Key<- DimReduc #' #' @examples #' # Set the key for DimReduc #' Key(object = pbmc_small[["pca"]]) <- "newkey2_" #' Key(object = pbmc_small[["pca"]]) #' "Key<-.DimReduc" <- function(object, ..., value) { op <- options(Seurat.object.validate = FALSE) on.exit(expr = options(op), add = TRUE) old <- Key(object = object) suppressWarnings(expr = object <- NextMethod(), classes = 'validationWarning') for (i in c("cell.embeddings", "feature.loadings", "feature.loadings.projected")) { mat <- slot(object = object, name = i) if (IsMatrixEmpty(x = mat)) { next } colnames(x = mat) <- gsub( pattern = paste0('^', old), replacement = Key(object = object), x = colnames(x = mat) ) slot(object = object, name = i) <- mat } options(op) validObject(object = object) return(object) } #' @param projected Pull the projected feature loadings? #' #' @rdname Loadings #' @export #' @method Loadings DimReduc #' #' @examples #' # Get the feature loadings for a given DimReduc #' Loadings(object = pbmc_small[["pca"]])[1:5,1:5] #' Loadings.DimReduc <- function(object, projected = FALSE, ...) { CheckDots(...) projected <- projected %||% Projected(object = object) slot <- ifelse( test = projected, yes = 'feature.loadings.projected', no = 'feature.loadings' ) return(slot(object = object, name = slot)) } #' @rdname Loadings #' @export #' @method Loadings<- DimReduc #' #' @examples #' # Set the feature loadings for a given DimReduc #' new.loadings <- Loadings(object = pbmc_small[["pca"]]) #' new.loadings <- new.loadings + 0.01 #' Loadings(object = pbmc_small[["pca"]]) <- new.loadings #' "Loadings<-.DimReduc" <- function(object, projected = TRUE, ..., value) { CheckDots(...) slot.use <- ifelse( test = projected, yes = 'feature.loadings.projected', no = 'feature.loadings' ) if (ncol(x = value) != length(x = object)) { stop("New feature loadings must have the dimensions as currently calculated") } slot(object = object, name = slot.use) <- value return(object) } #' @rdname Misc #' @export #' @method Misc DimReduc #' Misc.DimReduc <- .Misc #' @rdname Misc #' @export #' @method Misc<- DimReduc #' "Misc<-.DimReduc" <- `.Misc<-` #' @rdname RenameCells #' @export #' @method RenameCells DimReduc #' #' @examples #' # Rename cells in a DimReduc #' head(x = Cells(x = pbmc_small[["pca"]])) #' renamed.dimreduc <- RenameCells( #' object = pbmc_small[["pca"]], #' new.names = paste0("A_", Cells(x = pbmc_small[["pca"]])) #' ) #' head(x = Cells(x = renamed.dimreduc)) #' RenameCells.DimReduc <- function(object, new.names = NULL, ...) { CheckDots(...) old.data <- Embeddings(object = object) rownames(x = old.data) <- new.names slot(object = object, name = "cell.embeddings") <- old.data validObject(object = object) return(object) } #' @rdname Stdev #' @export #' @method Stdev DimReduc #' #' @examples #' # Get the standard deviations for each PC from the DimReduc object #' Stdev(object = pbmc_small[["pca"]]) #' Stdev.DimReduc <- function(object, ...) { CheckDots(...) return(slot(object = object, name = 'stdev')) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for R-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' Get Feature Loadings #' #' Pull feature loadings from a \link[=DimReduc]{dimensional reduction} #' #' \code{[} does not distinguish between projected and unprojected feature #' loadings; to select whether projected or unprojected loadings should be #' pulled, please use \code{\link{Loadings}} #' #' @param x A \code{\link{DimReduc}} object #' @param i Feature identifiers or indices #' @param j Dimension identifiers or indices #' @param drop Coerce the result to the lowest possible dimension; see #' \code{\link{drop}} for further details #' @template param-dots-method #' #' @return Feature loadings for features \code{i} and dimensions \code{j} #' #' @method [ DimReduc #' @export #' #' @family dimreduc #' #' @seealso \code{\link{Loadings}} #' #' @examples #' pca <- pbmc_small[["pca"]] #' pca[1:10, 1:5] #' "[.DimReduc" <- function(x, i, j, drop = FALSE, ...) { loadings <- Loadings(object = x) if (missing(x = i)) { i <- 1:nrow(x = loadings) } if (missing(x = j)) { j <- names(x = x) } else if (is.numeric(x = j)) { j <- names(x = x)[j] } bad.j <- j[!j %in% colnames(x = loadings)] j <- j[!j %in% bad.j] if (length(x = j) == 0) { stop("None of the requested loadings are present.") } if (length(x = bad.j) > 0) { warning( "The following loadings are not present: ", paste(bad.j, collapse = ", ") ) } return(Loadings(object = x)[i, j, drop = drop, ...]) } #' Get Cell Embeddings #' #' Pull cell embeddings from a \link[=DimReduc]{dimensional reduction} #' #' @inheritParams [.DimReduc #' @param i Cell names or indices #' #' @return Cell embeddings for cells \code{i} and dimensions \code{j} #' #' @method [[ DimReduc #' @export #' #' @family dimreduc #' #' @seealso \code{\link{Embeddings}} #' #' @examples #' pca <- pbmc_small[["pca"]] #' pca[[1:10, 1:5]] #' "[[.DimReduc" <- function(x, i, j, drop = FALSE, ...) { if (missing(x = i)) { i <- 1:nrow(x = x) } if (missing(x = j)) { j <- names(x = x) } else if (is.numeric(x = j)) { j <- names(x = x)[j] } embeddings <- Embeddings(object = x) bad.j <- j[!j %in% colnames(x = embeddings)] j <- j[!j %in% bad.j] if (length(x = j) == 0) { stop("None of the requested embeddings are present.") } if (length(x = bad.j) > 0) { warning( "The following embeddings are not present: ", paste(bad.j, collapse = ", ") ) } return(embeddings[i, j, drop = drop, ...]) } #' Dimensional Reduction Meta-Information #' #' Pull meta-information about cells and dimensions for a given #' \link[=DimReduc]{dimensional reduction}; cell meta-information is stored #' as row meta-information (eg. \code{nrow}, \code{rownames}) and dimension #' meta-information is stored as column meta-information (eg. \code{ncol}, #' \code{colnames}) #' #' @inheritParams [.DimReduc #' #' @return \code{dim}: The number of cells (\code{nrow}) and dimensions #' (\code{ncol}) #' #' @method dim DimReduc #' @export #' #' @family dimreduc #' #' @examples #' pca <- pbmc_small[["pca"]] #' pca #' dim(pca) #' #' # nrow is number of cells #' nrow(pca) #' #' # rownames pulls cell names #' head(rownames(pca)) #' #' # ncol and length are number of dimensions #' ncol(pca) #' length(pca) #' #' # colnames and names pull dimension identifiers #' head(colnames(pca)) #' head(names(pca)) #' dim.DimReduc <- function(x) { return(dim(x = Embeddings(object = x))) } #' @return \code{dimnames}: The cell (row) and dimension (column) names #' #' @rdname dim.DimReduc #' #' @method dimnames DimReduc #' @export #' #' @seealso \code{Cells} #' dimnames.DimReduc <- function(x) { return(dimnames(x = Embeddings(object = x))) } #' @return \code{length}: The number of dimensions #' #' @rdname dim.DimReduc #' #' @export #' @method length DimReduc #' length.DimReduc <- function(x) { return(ncol(x = x)) } #' Merge Dimensional Reductions #' #' Merge two or more \link[=DimReduc]{dimensional reduction} together #' #' @inheritParams [.DimReduc #' @inheritParams merge.Assay5 #' @param y One or more \code{\link{DimReduc}} objects #' @template param-dots-ignored #' #' @return A new \code{DimReduc} object with data merged from \code{c(x, y)} #' #' @method merge DimReduc #' @export #' #' @family dimreduc #' merge.DimReduc <- function( x = NULL, y = NULL, add.cell.ids = NULL, ... ) { CheckDots(...) drs <- c(x, y) if (!is.null(x = add.cell.ids)) { add.cell.ids <- unique(x = add.cell.ids) if (!is_bare_character(x = add.cell.ids, n = length(x = drs))) { abort( message = "'add.cell.ids' must be unique for every dimensional reduction" ) } for (i in seq_along(along.with = drs)) { drs[[i]] <- RenameCells(object = drs[[i]], new.names = add.cell.ids[i]) } } all.cells <- unlist(x = lapply(X = drs, FUN = Cells)) if (anyDuplicated(x = all.cells)) { abort(message = "Duplicate cells in provided dimensional reductions") } embeddings.mat <- lapply(X = drs, FUN = Embeddings) min.dim <- vapply( X = embeddings.mat, FUN = ncol, FUN.VALUE = integer(length = 1L), USE.NAMES = FALSE ) # embeddings.mat <- list() # min.dim <- c() # for (i in 1:length(x = drs)) { # embeddings.mat[[i]] <- Embeddings(object = drs[[i]]) # min.dim <- c(min.dim, ncol(x = embeddings.mat[[i]])) # } if (length(x = unique(x = min.dim)) > 1) { min.dim <- min(min.dim) warn(message = paste( "Reductions contain differing numbers of dimensions, merging first", min.dim )) # warning( # "Reductions contain differing numbers of dimensions, merging first ", # min.dim, # call. = FALSE, # immediate. = TRUE # ) embeddings.mat <- lapply( X = embeddings.mat, FUN = function(x) { return(x[, 1:min.dim]) } ) } embeddings.mat <- do.call(what = rbind, args = embeddings.mat) merged.dr <- CreateDimReducObject( embeddings = embeddings.mat, loadings = Loadings(object = drs[[1]], projected = FALSE), projected = Loadings(object = drs[[1]], projected = TRUE), assay = DefaultAssay(object = drs[[1]]), key = Key(object = drs[[1]]), global = IsGlobal(object = drs[[1]]) ) return(merged.dr) } #' @return \code{names}: The dimension identifiers #' #' @rdname dim.DimReduc #' #' @method names DimReduc #' @export #' names.DimReduc <- function(x) { # return(colnames(x = Embeddings(object = x))) return(colnames(x = x)) } #' Print Top Feature Loadings #' #' Prints a set of features that most strongly define a set of components; #' \strong{note}: requires feature loadings to be present in order to work #' #' @inheritParams [.DimReduc #' @param dims Number of dimensions to display #' @param nfeatures Number of genes to display #' @param projected Use projected slot #' @template param-dots-ignored #' #' @return Displays set of features defining the components and #' invisibly returns \code{x} #' #' @method print DimReduc #' @export #' #' @aliases print #' #' @family dimreduc #' #' @seealso \code{\link[base]{cat}} #' #' @examples #' pca <- pbmc_small[["pca"]] #' print(pca) #' print.DimReduc <- function( x, dims = 1:5, nfeatures = 20, projected = FALSE, ... ) { CheckDots(...) loadings <- Loadings(object = x, projected = projected) if (!IsMatrixEmpty(x = loadings)) { nfeatures <- min(nfeatures, nrow(x = loadings)) if (ncol(x = loadings) == 0) { warning("Dimensions have not been projected. Setting projected = FALSE") projected <- FALSE loadings <- Loadings(object = x, projected = projected) } if (min(dims) > ncol(x = loadings)) { stop("Cannot print dimensions greater than computed") } if (max(dims) > ncol(x = loadings)) { warning("Only ", ncol(x = loadings), " dimensions have been computed.") dims <- intersect(x = dims, y = seq_len(length.out = ncol(x = loadings))) } for (dim in dims) { features <- Top( data = loadings[, dim, drop = FALSE], num = nfeatures * 2, balanced = TRUE ) cat(Key(object = x), dim, '\n') pos.features <- split( x = features$positive, f = ceiling(x = seq_along(along.with = features$positive) / 10) ) cat("Positive: ", paste(pos.features[[1]], collapse = ", "), '\n') pos.features[[1]] <- NULL if (length(x = pos.features) > 0) { for (i in pos.features) { cat("\t ", paste(i, collapse = ", "), '\n') } } neg.features <- split( x = features$negative, f = ceiling(x = seq_along(along.with = features$negative) / 10) ) cat("Negative: ", paste(neg.features[[1]], collapse = ", "), '\n') neg.features[[1]] <- NULL if (length(x = neg.features) > 0) { for (i in neg.features) { cat("\t ", paste(i, collapse = ", "), '\n') } } } } return(invisible(x = x)) } #' Subset a Dimensional Reduction #' #' Subset a \code{\link{DimReduc}} object #' #' @inheritParams [.DimReduc #' @param cells,features Cells and features to keep during the subset #' @template param-dots-ignored #' #' @return \code{x} for cells \code{cells} and features \code{features} #' #' @method subset DimReduc #' @export #' #' @family dimreduc #' subset.DimReduc <- function(x, cells = NULL, features = NULL, ...) { CheckDots(...) cells <- Cells(x = x) %iff% cells %||% Cells(x = x) if (all(is.na(x = cells))) { cells <- Cells(x = x) } else if (any(is.na(x = cells))) { warn(message = "NAs passed in cells vector, removing NAs") cells <- na.omit(object = cells) } # features <- rownames(x = x) %iff% features %||% rownames(x = x) features <- rownames(x = Loadings(object = x)) %iff% features %||% rownames(x = Loadings(object = x)) if (all(sapply(X = list(features, cells), FUN = length) == dim(x = x))) { return(x) } slot(object = x, name = 'cell.embeddings') <- if (is.null(x = cells)) { new(Class = 'matrix') } else { if (is.numeric(x = cells)) { cells <- Cells(x = x)[cells] } cells <- intersect(x = Cells(x = x), y = cells) if (length(x = cells) == 0) { stop("Cannot find cell provided", call. = FALSE) } x[[cells, , drop = FALSE]] } slot(object = x, name = 'feature.loadings') <- if (is.null(x = features)) { new(Class = 'matrix') } else { if (is.numeric(x = features)) { features <- rownames(x = x)[features] } features.loadings <- intersect( x = rownames(x = Loadings(object = x, projected = FALSE)), y = features ) if (length(x = features.loadings) == 0) { stop("Cannot find features provided", call. = FALSE) } Loadings(object = x, projected = FALSE)[features.loadings, , drop = FALSE] } slot(object = x, name = 'feature.loadings.projected') <- if (is.null(x = features) || !Projected(object = x)) { new(Class = 'matrix') } else { features.projected <- intersect( x = rownames(x = Loadings(object = x, projected = TRUE)), y = features ) if (length(x = features.projected) == 0) { stop("Cannot find features provided", call. = FALSE) } Loadings(object = x, projected = TRUE)[features.projected, , drop = FALSE] } slot(object = x, name = 'jackstraw') <- new(Class = 'JackStrawData') return(x) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Internal #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% .RenameFeatures <- function(object, old.names = NULL, new.names = NULL) { if (is.null(x = old.names) && is.null(x = new.names)) { return(object) } # Checks op <- options(Seurat.object.validate = FALSE) on.exit(expr = options(op)) stopifnot(length(x = old.names) == length(x = new.names)) stopifnot(all(nzchar(x = old.names))) stopifnot(all(nzchar(x = new.names))) if (is.null(x = Features(x = object)) && length(x = new.names)) { warning("No features present in this DimReduc", call. = FALSE, immediate. = TRUE) } # Rename features names(x = new.names) <- old.names features <- Features(x = object, projected = FALSE) ldat <- Loadings(object = object, projected = FALSE) rownames(x = ldat) <- unname(obj = new.names[features]) Loadings(object = object, projected = FALSE) <- ldat if (isTRUE(x = Projected(object = object))) { pdat <- Loadings(object = object, projected = TRUE) pfeatures <- Features(x = object, projected = TRUE) rownames(x = pdat) <- unname(obj = new.names[pfeatures]) Loadings(object = object, projected = TRUE) <- pdat } # Validate and return options(op) validObject(object = object) return(object) } #' Check to see if projected loadings have been set #' #' @param object a DimReduc object #' #' @return TRUE if projected loadings have been set, else FALSE #' #' @keywords internal #' #' @noRd #' Projected <- function(object) { return(!IsMatrixEmpty(x = Loadings(object = object, projected = TRUE))) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # S4 methods #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' Dimensional Reduction Overview #' #' Overview of a \code{\link{DimReduc}} object #' #' @param object A dimensional reduction #' #' @template return-show #' #' @keywords internal #' #' @seealso \code{\link{DimReduc}} #' #' @examples #' pca <- pbmc_small[["pca"]] #' pca #' setMethod( f = 'show', signature = 'DimReduc', definition = function(object) { cat( "A dimensional reduction object with key", Key(object = object), '\n', 'Number of dimensions:', length(x = object), '\n', 'Number of cells:', length(x = Cells(x = object)), '\n', 'Projected dimensional reduction calculated: ', Projected(object = object), '\n', 'Jackstraw run:', as.logical(x = JS(object = object)), '\n', 'Computed using assay:', DefaultAssay(object = object), '\n' ) return(invisible(x = NULL)) } ) #' Dimensional Reduction Validity #' #' @templateVar cls DimReduc #' @template desc-validity #' #' @section Cell Embeddings Validation: #' The cell embeddings matrix must be a numeric matrix of dimensions #' \eqn{n_{cells}} by \eqn{d_{dimensions}}; row names must be the cell names #' and column names must be the dimension identifier. The dimension identifier #' must be \dQuote{\code{key_dimension}} (eg. \dQuote{\code{PC_1}}). Dimension #' identifiers must be in order and cannot be skipped #' #' @section Feature and Projected Feature Loadings Validation: #' blah #' #' @inheritSection Key-validity Key Validation #' #' @section Standard Deviations Validation: #' blah #' #' @name DimReduc-validity #' #' @family dimreduc #' setValidity( Class = 'DimReduc', method = function(object) { if (.GetSeuratCompat() < '5.0.0') { return(TRUE) } if (isFALSE(x = getOption(x = "Seurat.object.validate", default = TRUE))) { warn( message = paste("Not validating", class(x = object)[1L], "objects"), class = 'validationWarning' ) return(TRUE) } valid <- NULL ValidColnames <- function( mat, ref = NULL, type = c('embeddings', 'loadings', 'projected') ) { ret <- NULL if (IsMatrixEmpty(x = mat)) { return(ret) } type <- match.arg(arg = type) type <- switch( EXPR = type, embeddings = 'cell.embeddings', loadings = 'feature.loadings', projected = 'feature.loadings.projected' ) mat.names <- colnames(x = mat) key <- paste0('^', Key(object = object)) if (is.null(x = mat.names)) { ret <- c(ret, paste("colnames must be present in", sQuote(x = type))) } else if (!all(grepl(pattern = key, x = mat.names))) { ret <- c( ret, paste( "colnames for", sQuote(x = type), "must start with reduction key", paste0("(", Key(object = object), ")") ) ) } else { dims <- as.numeric(x = gsub(pattern = key, replacement = '', x = mat.names)) if (!is_bare_integerish(x = dims, n = ncol(x = mat), finite = TRUE) || any(dims < 1L)) { ret <- c( ret, paste( "dimension names for", sQuote(x = type), "must be positive integers" ) ) } else if (is.unsorted(x = dims)) { ret <- c( ret, paste("dimensions for", sQuote(x = type), "must be in order") ) } } if (!is.null(x = ref)) { if (length(x = mat.names) != length(x = ref)) { ret <- c( ret, paste(sQuote(x = type), "must have", length(x = ref), "dimensions") ) } else if (!all(mat.names == ref)) { ret <- c( ret, paste( "dimensions in", sQuote(x = type), "do not match dimensions in reduction" ) ) } } return(ret) } # Validate cell embeddings emb <- Embeddings(object = object) if (!is.numeric(x = emb)) { valid <- c(valid, "'cell.embeddings' must be a numeric matrix") } if (is.null(x = rownames(x = emb)) || !all(nzchar(x = rownames(x = emb)))) { valid <- c(valid, "rownames must be present in 'cell.embeddings'") } valid <- c(valid, ValidColnames(mat = emb, type = 'embeddings')) if (!is.null(x = valid)) { return(valid) } dims <- colnames(x = emb) # if (is.null(x = colnames(x = emb))) { # valid <- c(valid, "colnames must be present in 'cell.embeddings'") # } else { # emb.names <- colnames(x = emb) # if (!all(grepl(pattern = paste0('^', Key(object = object)), x = emb.names))) { # valid <- c( # valid, # paste0( # "colnames for 'cell.embeddings' must start with reduction key (", # Key(object = object), # ")" # ) # ) # } # } # if (!is.null(x = valid)) { # return(valid) # } # TODO: Validate feature loadings lds <- Loadings(object = object, projected = FALSE) valid <- c(valid, ValidColnames(mat = lds, type = 'loadings')) # TODO: Validate projected loadings prj <- Loadings(object = object, projected = TRUE) valid <- c(valid, ValidColnames(mat = prj, type = 'projected')) # TODO: Validate assay used if (!rlang::is_scalar_character(x = DefaultAssay(object = object))) { valid <- c(valid, "'assay.orig' must be a 1-length character") } # Validate globalness if (!rlang::is_scalar_logical(x = IsGlobal(object = object))) { valid <- c(valid, "'global' must be a 1-length logical") } else if (is_na(x = IsGlobal(object = object))) { valid <- c(valid, "'global' must be TRUE or FALSE") } # TODO: Validate standard deviations # TODO: Validate JackStraw data # TODO: Validate misc return(valid %||% TRUE) } ) SeuratObject/R/seurat.R0000644000176200001440000053046614525215076014520 0ustar liggesusers#' @include zzz.R #' @include generics.R #' @include assay.R #' @include command.R #' @include dimreduc.R #' @include graph.R #' @include spatial.R #' @importFrom methods setClass #' NULL #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Class definitions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' The Seurat Class #' #' The Seurat object is a representation of single-cell expression data for R; #' each Seurat object revolves around a set of cells and consists of one or more #' \code{\link{Assay}} objects, or individual representations of #' expression data (eg. RNA-seq, ATAC-seq, etc). These assays can be reduced #' from their high-dimensional state to a lower-dimension state and stored as #' \code{\link{DimReduc}} objects. Seurat objects also #' store additional metadata, both at the cell and feature level (contained #' within individual assays). The object was designed to be as self-contained as #' possible, and easily extendable to new methods. #' #' @slot assays A list of assays for this project #' @slot meta.data Contains meta-information about each cell, starting with #' number of features detected (nFeature) and the original identity class #' (orig.ident); more information is added using \code{\link{AddMetaData}} #' @slot active.assay Name of the active, or default, assay; settable using #' \code{\link{DefaultAssay}} #' @slot active.ident The active cluster identity for this Seurat object; #' settable using \code{\link{Idents}} #' @slot graphs A list of \code{\link{Graph}} objects #' @slot neighbors ... #' @slot reductions A list of dimensional reduction objects for this object #' @slot images A list of spatial image objects #' @slot project.name Name of the project #' @slot misc A list of miscellaneous information #' @slot version Version of Seurat this object was built under #' @slot commands A list of logged commands run on this \code{Seurat} object #' @slot tools A list of miscellaneous data generated by other tools, should be #' filled by developers only using \code{\link{Tool}<-} #' #' @name Seurat-class #' @rdname Seurat-class #' @exportClass Seurat #' #' @family seurat #' #' @aliases Seurat #' setClass( Class = 'Seurat', slots = c( assays = 'list', meta.data = 'data.frame', active.assay = 'character', active.ident = 'factor', graphs = 'list', neighbors = 'list', reductions = 'list', images = 'list', project.name = 'character', misc = 'list', version = 'package_version', commands = 'list', tools = 'list' ) ) #' The Seurat Class #' #' The Seurat object is the center of each single cell analysis. It stores all #' information associated with the dataset, including data, annotations, #' analyses, etc. All that is needed to construct a Seurat object is an #' expression matrix (rows are genes, columns are cells), which should #' be log-scale #' #' Each Seurat object has a number of slots which store information. Key slots #' to access are listed below. #' #' @slot raw.data The raw project data #' @slot data The normalized expression matrix (log-scale) #' @slot scale.data scaled (default is z-scoring each gene) expression matrix; #' used for dimensional reduction and heatmap visualization #' @slot var.genes Vector of genes exhibiting high variance across single cells #' @slot is.expr Expression threshold to determine if a gene is expressed #' (0 by default) #' @slot ident THe 'identity class' for each cell #' @slot meta.data Contains meta-information about each cell, starting with #' number of genes detected (nFeature) and the original identity class #' (orig.ident); more information is added using \code{AddMetaData} #' @slot project.name Name of the project (for record keeping) #' @slot dr List of stored dimensional reductions; named by technique #' @slot assay List of additional assays for multimodal analysis; named by #' technique #' @slot hvg.info The output of the mean/variability analysis for all genes #' @slot imputed Matrix of imputed gene scores #' @slot cell.names Names of all single cells #' (column names of the expression matrix) #' @slot cluster.tree List where the first element is a phylo object containing #' the phylogenetic tree relating different identity classes #' @slot snn Spare matrix object representation of the SNN graph #' @slot calc.params Named list to store all calculation-related #' parameter choices #' @slot kmeans Stores output of gene-based clustering from \code{DoKMeans} #' @slot spatial Stores internal data and calculations for spatial mapping of #' single cells #' @slot misc Miscellaneous spot to store any data alongside the object #' (for example, gene lists) #' @slot version Version of package used in object creation #' #' @name seurat-class #' @rdname oldseurat-class #' @aliases seurat-class oldseurat #' #' @concept unsorted #' @concept v2 #' #' @keywords internal #' setClass( Class = "seurat", slots = c( raw.data = "ANY", data = "ANY", scale.data = "ANY", var.genes = "vector", is.expr = "numeric", ident = "factor", meta.data = "data.frame", project.name = "character", dr = "list", assay = "list", hvg.info = "data.frame", imputed = "data.frame", cell.names = "vector", cluster.tree = "list", snn = "dgCMatrix", calc.params = "list", kmeans = "ANY", spatial = "ANY", misc = "ANY", version = "ANY" ) ) #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Functions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' Get cell names grouped by identity class #' #' @param object A Seurat object #' @param idents A vector of identity class levels to limit resulting list to; #' defaults to all identity class levels #' @param cells A vector of cells to grouping to #' @param return.null If no cells are requested, return a \code{NULL}; #' by default, throws an error #' #' @return A named list where names are identity classes and values are vectors #' of cells belonging to that class #' #' @export #' #' @concept data-access #' #' @examples #' CellsByIdentities(object = pbmc_small) #' CellsByIdentities <- function( object, idents = NULL, cells = NULL, return.null = FALSE ) { cells <- cells %||% colnames(x = object) cells <- intersect(x = cells, y = colnames(x = object)) if (length(x = cells) == 0) { if (isTRUE(x = return.null)) { return(NULL) } stop("Cannot find cells provided") } idents <- idents %||% levels(x = object) idents <- intersect(x = idents, y = levels(x = object)) if (length(x = idents) == 0) { stop("None of the provided identity class levels were found", call. = FALSE) } cells.idents <- sapply( X = idents, FUN = function(i) { return(cells[as.vector(x = Idents(object = object)[cells]) == i]) }, simplify = FALSE, USE.NAMES = TRUE ) if (any(is.na(x = Idents(object = object)[cells]))) { cells.idents[["NA"]] <- names(x = which(x = is.na(x = Idents(object = object)[cells]))) } return(cells.idents) } #' Get a vector of cell names associated with an image (or set of images) #' #' @param object Seurat object #' @param images Vector of image names #' @param unlist Return as a single vector of cell names as opposed to a list, #' named by image name. #' #' @return A vector of cell names #' #' @concept data-access #' #' @examples #' \dontrun{ #' CellsByImage(object = object, images = "slice1") #' } #' CellsByImage <- function(object, images = NULL, unlist = FALSE) { images <- images %||% Images(object = object) cells <- sapply( X = images, FUN = function(x) { Cells(x = object[[x]]) }, simplify = FALSE, USE.NAMES = TRUE ) if (unlist) { cells <- unname(obj = unlist(x = cells)) } return(cells) } #' Find Sub-objects of a Certain Class #' #' Get the names of objects within a \code{Seurat} object that are of a #' certain class #' #' @param object A \code{\link{Seurat}} object #' @param classes.keep A vector of names of classes to get #' #' @return A vector with the names of objects within the \code{Seurat} object #' that are of class \code{classes.keep} #' #' @export #' #' @concept utils #' #' @templateVar fxn FilterObjects #' @templateVar ver 5.0.0 #' @templateVar repl .FilterObjects #' @template lifecycle-deprecated #' #' @examples #' FilterObjects(pbmc_small) #' FilterObjects <- function( object, classes.keep = c('Assay', 'StdAssay', 'DimReduc') ) { .Deprecate(when = '5.0.0', what = 'FilterObjects()', with = '.FilterObjects()') object <- UpdateSlots(object = object) slots <- na.omit(object = Filter( f = function(x) { sobj <- slot(object = object, name = x) return(is.list(x = sobj) && !is.data.frame(x = sobj) && !is.package_version(x = sobj)) }, x = slotNames(x = object) )) slots <- grep(pattern = 'tools', x = slots, value = TRUE, invert = TRUE) slots <- grep(pattern = 'misc', x = slots, value = TRUE, invert = TRUE) slots.objects <- unlist( x = lapply( X = slots, FUN = function(x) { return(names(x = slot(object = object, name = x))) } ), use.names = FALSE ) object.classes <- sapply( X = slots.objects, FUN = function(i) { return(inherits(x = object[[i]], what = classes.keep)) } ) object.classes <- which(x = object.classes, useNames = TRUE) return(names(x = object.classes)) } #' @rdname ObjectAccess #' @export #' #' @examples #' Graphs(pbmc_small) #' Graphs <- function(object, slot = NULL) { graphs <- .FilterObjects(object = object, classes.keep = "Graph") if (is.null(x = slot)) { return(graphs) } if (!slot %in% graphs) { warning( "Cannot find a Graph object of name ", slot, " in this Seurat object", call. = FALSE, immediate. = TRUE ) } return(slot(object = object, name = 'graphs')[[slot]]) } #' Pull spatial image names #' #' List the names of \code{SpatialImage} objects present in a \code{Seurat} #' object. If \code{assay} is provided, limits search to images associated with #' that assay #' #' @param object A \code{Seurat} object #' @param assay Name of assay to limit search to #' #' @return A list of image names #' #' @export #' #' @concept data-access #' #' @examples #' \dontrun{ #' Images(object) #' } #' Images <- function(object, assay = NULL) { images <- names(x = slot(object = object, name = 'images')) if (!is.null(x = assay)) { assays <- c(assay, DefaultAssay(object = object[[assay]])) images <- Filter( f = function(x) { return(DefaultAssay(object = object[[x]]) %in% assays) }, x = images ) } return(images) } #' @inheritDotParams base::readRDS #' #' @rdname SaveSeuratRds #' @export #' LoadSeuratRds <- function(file, ...) { object <- readRDS(file = file, ...) cache <- Tool(object = object, slot = 'SaveSeuratRds') reqd.cols <- c('layer', 'path', 'class', 'pkg', 'fxn', 'assay') emit <- ifelse( test = isTRUE(x = getOption(x = 'Seurat.io.rds.strict', default = FALSE)), yes = abort, no = warn ) if (!is.null(x = cache)) { if (interactive()) { check_installed(pkg = 'fs', reason = 'for finding file paths') } else if (!requireNamespace('fs', quietly = TRUE)) { abort(message = "Loading layers from disk requires `fs`") } # Check the format of the cache if (!is.data.frame(x = cache)) { emit(message = "Malformed layer cache: not a data frame") return(object) } if (!all(reqd.cols %in% names(x = cache))) { emit(message = "Malformed layer cache: missing required columns") return(object) } # Check the assays specified assays <- .FilterObjects(object = object, classes.keep = 'StdAssay') cache <- cache[cache$assay %in% assays, , drop = FALSE] if (!nrow(x = cache)) { emit(message = "Incorrect layer cache: none of the assays listed present") return(object) } # Check the files exists <- vapply( X = cache$path, FUN = function(x) { x <- unlist(x = strsplit(x = x, split = ',')) res <- vector(mode = 'logical', length = length(x = x)) for (i in seq_along(along.with = x)) { res[i] <- fs::is_file(path = x[i]) || fs::dir_exists(path = x[i]) } return(all(res)) }, FUN.VALUE = logical(length = 1L), USE.NAMES = FALSE ) exists[is.na(exists)] <- FALSE cache <- cache[exists, , drop = FALSE] if (!nrow(x = cache)) { emit(message = "Cannot find any of the layer files specified") return(object) } # Check the packages missing.pkgs <- pkgs <- unique(x = cache$pkg) for (pkg in pkgs) { if (interactive()) { check_installed(pkg = pkg) } if (requireNamespace(pkg, quietly = TRUE)) { missing.pkgs <- setdiff(x = missing.pkgs, y = pkg) } else { emit(message = paste("Cannot find required package:", sQuote(x = pkg))) } } pkgs <- setdiff(x = pkgs, y = missing.pkgs) if (!length(x = pkgs)) { emit(message = "None of the required layer packages found") return(object) } p <- progressor(steps = nrow(x = cache)) # Load the layers for (i in seq_len(length.out = nrow(x = cache))) { lyr <- cache$layer[i] pth <- cache$path[i] fxn <- eval(expr = str2lang(s = cache$fxn[i])) assay <- cache$assay[i] p( message = paste( "Adding layer", sQuote(x = lyr), "to assay", sQuote(x = assay) ), class = 'sticky', amount = 0 ) LayerData(object = object, assay = assay, layer = lyr) <- fxn(pth) p() } } return(object) } #' @rdname ObjectAccess #' @export #' Neighbors <- function(object, slot = NULL) { neighbors <- .FilterObjects(object = object, classes.keep = "Neighbor") if (is.null(x = slot)) { return(neighbors) } if (!slot %in% neighbors) { warning( "Cannot find a Neighbor object of name ", slot, " in this Seurat object", call. = FALSE, immediate. = TRUE ) } return(slot(object = object, name = 'neighbors')[[slot]]) } #' @rdname ObjectAccess #' @export #' #' @examples #' Reductions(object = pbmc_small) #' Reductions <- function(object, slot = NULL) { reductions <- .FilterObjects(object = object, classes.keep = 'DimReduc') if (is.null(x = slot)) { return(reductions) } if (!slot %in% reductions) { warn( message = paste( 'Cannot find a DimReduc of name', slot, 'in this Seurat object') ) return(NULL) } return(slot(object = object, name = 'reductions')[[slot]]) } #' Rename assays in a \code{Seurat} object #' #' @param object A \code{Seurat} object #' @param assay.name original name of assay #' @param new.assay.name new name of assay #' @param verbose Whether to print messages #' @param ... Named arguments as \code{old.assay = new.assay} #' #' @return \code{object} with assays renamed #' #' @export #' #' @concept seurat #' #' @examples #' RenameAssays(object = pbmc_small, RNA = 'rna') #' RenameAssays <- function( object, assay.name = NULL, new.assay.name = NULL, verbose = TRUE, ...) { op <- options(Seurat.object.assay.calcn = FALSE) on.exit(expr = options(op), add = TRUE) if ((!is.null(x = assay.name) & is.null(x = new.assay.name)) | (is.null(x = assay.name) & !is.null(x = new.assay.name))) { stop("Must provide both assay.name and new.assasy.name if using parameters. Otherwise, ", "you can set arguments without parameters by doing ", "{old.assay = new.assay} with your own assay names.", call. = FALSE) } if (!is.null(x = assay.name) & !is.null(x = new.assay.name)) { assay.pairs <- new.assay.name names(x = assay.pairs) <- assay.name old.assays <- names(x = assay.pairs) } else { assay.pairs <- tryCatch( expr = as.list(x = ...), error = function(e) { return(list(...)) } ) old.assays <- names(x = assay.pairs) names(x = assay.pairs) <- old.assays } # Handle missing assays missing.assays <- setdiff(x = old.assays, y = Assays(object = object)) if (length(x = missing.assays) == length(x = old.assays)) { stop("None of the assays provided are present in this object", call. = FALSE) } else if (length(x = missing.assays)) { warning( "The following assays could not be found: ", paste(missing.assays, collapse = ', '), call. = FALSE, immediate. = TRUE ) } old.assays <- setdiff(x = old.assays, missing.assays) assay.pairs <- assay.pairs[old.assays] # Check to see that all old assays are named if (is.null(x = names(x = assay.pairs)) || any(sapply(X = old.assays, FUN = nchar) < 1)) { stop("All arguments must be named with the old assay name", call. = FALSE) } # Ensure each old assay is going to one new assay if (!all(sapply(X = assay.pairs, FUN = length) == 1) || length(x = old.assays) != length(x = unique(x = old.assays))) { stop("Can only rename assays to one new name", call. = FALSE) } # Ensure each new assay is coming from one old assay if (length(x = assay.pairs) != length(x = unique(x = assay.pairs))) { stop( "One or more assays are set to be lost due to duplicate new assay names", call. = FALSE ) } # Rename assays for (old in names(x = assay.pairs)) { new <- assay.pairs[[old]] # If we aren't actually renaming any if (old == new) { next } old.key <- Key(object = object[[old]]) suppressWarnings(expr = object[[new]] <- object[[old]]) if (old == DefaultAssay(object = object)) { if (verbose) { message("Renaming default assay from ", old, " to ", new) } DefaultAssay(object = object) <- new } Key(object = object[[new]]) <- old.key # change assay used in any dimreduc object for (i in Reductions(object = object)) { if (DefaultAssay(object = object[[i]]) == old) { DefaultAssay(object = object[[i]]) <- new } } # Add new metadata if it exists if (isTRUE(paste0("nCount_", old) %in% colnames(object[[]]))) { slot( object = object, name = 'meta.data' )[paste0("nCount_", new)] <- object[[]][,paste0("nCount_",old)] } if (isTRUE(paste0("nFeature_", old) %in% colnames(object[[]]))) { slot( object = object, name = 'meta.data' )[paste0("nFeature_", new)] <- object[[]][,paste0("nFeature_", old)] } object[[old]] <- NULL } return(object) } #' Save and Load \code{Seurat} Objects from Rds files #' #' @param object A \code{\link{Seurat}} object #' @param file Path to save \code{object} to; defaults to #' \code{file.path(getwd(), paste0(Project(object), ".Rds"))} #' @param move Move on-disk layers into \code{dirname(file)} #' @param destdir \Sexpr[stage=build,results=rd]{lifecycle::badge("deprecated")} #' @param relative Save relative paths instead of absolute ones #' @inheritDotParams base::saveRDS #' #' @return Invisibly returns \code{file} #' #' @export #' #' @template section-progressr #' #' @templateVar pkg fs #' @template note-reqdpkg #' #' @concept utils #' #' @seealso \code{\link{saveRDS}()} \code{\link{readRDS}()} #' #' @order 1 #' #' @examples #' if (requireNamespace("fs", quietly = TRUE)) { #' # Write out with DelayedArray #' if (requireNamespace("HDF5Array", quietly = TRUE)) { #' pbmc <- pbmc_small #' #' pbmc[["disk"]] <- CreateAssay5Object(list( #' mem = LayerData(pbmc, "counts"), #' disk = as(LayerData(pbmc, "counts"), "HDF5Array") #' )) #' #' # Save `pbmc` to an Rds file #' out <- tempfile(fileext = ".Rds") #' SaveSeuratRds(pbmc, file = out) #' #' # Object cache #' obj <- readRDS(out) #' Tool(obj, "SaveSeuratRds") #' #' # Load the saved object with on-disk layers back into memory #' pbmc2 <- LoadSeuratRds(out) #' pbmc2 #' pbmc2[["disk"]] #' } #' #' # Write out with BPCells #' if (requireNamespace("BPCells", quietly = TRUE)) { #' pbmc <- pbmc_small #' #' bpm <- BPCells::write_matrix_dir(LayerData(pbmc, "counts"), dir = tempfile()) #' bph <- BPCells::write_matrix_hdf5( #' LayerData(pbmc, "counts"), #' path = tempfile(fileext = ".h5"), #' group = "counts" #' ) #' pbmc[["disk"]] <- CreateAssay5Object(list(dir = bpm, h5 = bph)) #' #' # Save `pbmc` to an Rds file #' out <- tempfile(fileext = ".Rds") #' SaveSeuratRds(pbmc, file = out) #' #' # Object cache #' obj <- readRDS(out) #' Tool(obj, "SaveSeuratRds") #' #' # Load the saved object with on-disk layers back into memory #' pbmc2 <- LoadSeuratRds(out) #' pbmc2 #' pbmc2[["disk"]] #' } #' } #' SaveSeuratRds <- function( object, file = NULL, move = TRUE, destdir = deprecated(), relative = FALSE, ... ) { file <- file %||% file.path(getwd(), paste0(Project(object = object), '.Rds')) file <- normalizePath(path = file, winslash = '/', mustWork = FALSE) if (is_present(arg = destdir)) { .Deprecate( when = '5.0.1', what = 'SaveSeuratRds(destdir = )', with = 'SaveSeuratRds(move = )', details = paste( "Specifying a directory to move on-disk layers stored in", sQuote(x = normalizePath(path = tempdir(), winslash = '/', mustWork = FALSE)), "is deprecated; now, specify `move = TRUE` either move all on-disk layers to", sQuote(x = dirname(path = file)), "or `move = FALSE` leave them as-is" ) ) move <- is_bare_character(x = destdir, n = 1L) || is.null(x = destdir) } # Cache v5 assays assays <- .FilterObjects(object = object, classes.keep = 'StdAssay') p <- progressor(along = assays, auto_finish = TRUE) on.exit(expr = p(type = 'finish'), add = TRUE) p( message = paste( "Looking for on-disk matrices in", length(x = assays), "assays" ), class = 'sticky', amount = 0 ) cache <- vector(mode = 'list', length = length(x = assays)) names(x = cache) <- assays destdir <- dirname(path = file) if (isTRUE(x = move)) { check_installed(pkg = 'fs', reason = 'for moving on-disk matrices') } for (assay in assays) { p( message = paste("Searching through assay", assay), class = 'sticky', amount = 0 ) df <- lapply( X = Layers(object = object[[assay]]), FUN = function(lyr) { ldat <- LayerData(object = object[[assay]], layer = lyr) path <- .FilePath(x = ldat) path <- Filter(f = nzchar, x = path) if (!length(x = path)) { path <- NULL } if (is.null(x = path)) { return(NULL) } return(data.frame( layer = lyr, path = path, class = paste(class(x = ldat), collapse = ','), pkg = .ClassPkg(object = ldat), fxn = .DiskLoad(x = ldat) %||% identity )) } ) df <- do.call(what = 'rbind', args = df) if (is.null(x = df) || !nrow(x = df)) { p(message = "No on-disk layers found", class = 'sticky', amount = 0) next } if (isTRUE(x = move)) { for (i in seq_len(length.out = nrow(x = df))) { pth <- df$path[i] p( message = paste( "Moving layer", sQuote(x = df$layer[i]), "to", sQuote(x = destdir) ), class = 'sticky', amount = 0 ) df[i, 'path'] <- as.character(x = .FileMove( path = pth, new_path = destdir )) } } if (isTRUE(x = relative)) { p( message = paste( "Adjusting paths to be relative to", sQuote(x = dirname(path = file), q = FALSE) ), class = 'sticky', amount = 0 ) df$path <- as.character(x = fs::path_rel( path = df$path, start = dirname(path = file) )) } df$assay <- assay cache[[assay]] <- df if (nrow(x = df) == length(x = Layers(object = object[[assay]]))) { p( message = paste("Clearing layers from", assay), class = 'sticky', amount = 0 ) adata <- S4ToList(object = object[[assay]]) adata$layers <- list() adata$default <- 0L adata$cells <- LogMap(y = colnames(x = object[[assay]])) adata$features <- LogMap(y = rownames(x = object[[assay]])) object[[assay]] <- ListToS4(x = adata) } else { p( message = paste("Clearing", nrow(x = df), "layers from", assay), class = 'sticky', amount = 0 ) for (layer in df$layer) { LayerData(object = object[[assay]], layer = layer) <- NULL } } p() } cache <- do.call(what = 'rbind', args = cache) if (!is.null(x = cache) && nrow(x = cache)) { p(message = "Saving on-disk cache to object", class = 'sticky', amount = 0) row.names(x = cache) <- NULL Tool(object = object) <- cache } saveRDS(object = object, file = file, ...) return(invisible(x = file)) } #' Update old Seurat object to accommodate new features #' #' Updates Seurat objects to new structure for storing data/calculations. #' For Seurat v3 objects, will validate object structure ensuring all keys #' and feature names are formed properly. #' #' @param object Seurat object #' #' @return Returns a Seurat object compatible with latest changes #' #' @importFrom methods .hasSlot new slot #' #' @export #' #' @concept seurat #' #' @examples #' \dontrun{ #' updated_seurat_object = UpdateSeuratObject(object = old_seurat_object) #' } #' UpdateSeuratObject <- function(object) { op <- options(Seurat.object.validate = FALSE) on.exit(expr = options(op), add = TRUE) if (.hasSlot(object, "version")) { if (slot(object = object, name = 'version') >= package_version(x = "2.0.0") && slot(object = object, name = 'version') < package_version(x = '3.0.0')) { # Run update message("Updating from v2.X to v3.X") # seurat.version <- packageVersion(pkg = "SeuratObject") seurat.version <- package_version(x = '3.0.0') new.assay <- UpdateAssay(old.assay = object, assay = "RNA") assay.list <- list(new.assay) names(x = assay.list) <- "RNA" for (i in names(x = object@assay)) { assay.list[[i]] <- UpdateAssay(old.assay = object@assay[[i]], assay = i) } new.dr <- UpdateDimReduction(old.dr = object@dr, assay = "RNA") object <- new( Class = "Seurat", version = seurat.version, assays = assay.list, active.assay = "RNA", project.name = object@project.name, misc = object@misc %||% list(), active.ident = object@ident, reductions = new.dr, meta.data = object@meta.data, tools = list() ) # Run CalcN for (assay in Assays(object = object)) { n.calc <- CalcN(object = object[[assay]]) if (!is.null(x = n.calc)) { names(x = n.calc) <- paste(names(x = n.calc), assay, sep = '_') object[[names(x = n.calc)]] <- n.calc } to.remove <- c("nGene", "nUMI") for (i in to.remove) { if (i %in% colnames(x = object[[]])) { object[[i]] <- NULL } } } } if (package_version(x = slot(object = object, name = 'version')) >= package_version(x = "3.0.0")) { # Run validation message("Validating object structure") # Update object slots message("Updating object slots") object <- UpdateSlots(object = object) # Validate object keys message("Ensuring keys are in the proper structure") for (ko in .FilterObjects(object = object)) { key <- Key(object = object[[ko]]) if (!length(x = key) || !nzchar(x = key)) { key <- Key(object = ko, quiet = TRUE) } slot( object = slot(object = object, name = FindObject(object, ko))[[ko]], name = 'key' ) <- UpdateKey(key) if (inherits(x = slot(object = object, name = FindObject(object, ko))[[ko]], what = 'DimReduc')) { message("Updating matrix keys for DimReduc ", sQuote(ko)) for (m in c('cell.embeddings', 'feature.loadings', 'feature.loadings.projected')) { mat <- slot( object = slot(object = object, name = FindObject(object, ko))[[ko]], name = m ) if (IsMatrixEmpty(mat)) { next } colnames(x = mat) <- paste0(key, seq_len(ncol(mat))) slot( object = slot(object = object, name = FindObject(object, ko))[[ko]], name = m ) <- mat } } } # Rename assays assays <- make.names(names = Assays(object = object)) names(x = assays) <- Assays(object = object) object <- do.call(what = RenameAssays, args = c('object' = object, assays)) for (obj in .FilterObjects(object = object, classes.keep = c('Assay', 'DimReduc', 'Graph'))) { suppressWarnings( expr = object[[obj]] <- UpdateSlots(object = object[[obj]]), classes = 'validationWarning' ) } for (cmd in Command(object = object)) { slot(object = object, name = 'commands')[[cmd]] <- UpdateSlots( object = Command(object = object, command = cmd) ) } # Validate object keys message("Ensuring keys are in the proper structure") for (ko in .FilterObjects(object = object)) { suppressWarnings( expr = Key(object = object[[ko]]) <- UpdateKey(key = Key(object = object[[ko]])), classes = 'validationWarning' ) } # Check feature names message("Ensuring feature names don't have underscores or pipes") for (assay.name in .FilterObjects(object = object, classes.keep = 'Assay')) { assay <- object[[assay.name]] for (slot in c('counts', 'data', 'scale.data')) { if (!IsMatrixEmpty(x = slot(object = assay, name = slot))) { rownames(x = slot(object = assay, name = slot)) <- gsub( pattern = '_', replacement = '-', x = rownames(x = slot(object = assay, name = slot)) ) rownames(x = slot(object = assay, name = slot)) <- gsub( pattern = '|', replacement = '-', x = rownames(x = slot(object = assay, name = slot)), fixed = TRUE ) } } VariableFeatures(object = assay) <- gsub( pattern = '_', replacement = '-', x = VariableFeatures(object = assay) ) VariableFeatures(object = assay) <- gsub( pattern = '|', replacement = '-', x = VariableFeatures(object = assay), fixed = TRUE ) rownames(x = slot(object = assay, name = "meta.features")) <- gsub( pattern = '_', replacement = '-', x = rownames(x = assay[[]]) ) rownames(x = slot(object = assay, name = "meta.features")) <- gsub( pattern = '|', replacement = '-', x = rownames(x = assay[[]]), fixed = TRUE ) # reorder features in scale.data and meta.features to match counts sd.features <- rownames(x = slot(object = assay, name = "scale.data")) data.features <- rownames(x = slot(object = assay, name = "data")) md.features <- rownames(x = slot(object = assay, name = "meta.features")) if (!all.equal(target = md.features, current = data.features, check.attributes = FALSE)) { slot(object = assay, name = "meta.features") <- slot(object = assay, name = "meta.features")[data.features, ] } sd.order <- sd.features[order(match(x = sd.features, table = data.features))] slot(object = assay, name = "scale.data") <- slot(object = assay, name = "scale.data")[sd.order, ] suppressWarnings( expr = object[[assay.name]] <- assay, classes = 'validationWarning' ) } for (reduc.name in .FilterObjects(object = object, classes.keep = 'DimReduc')) { reduc <- object[[reduc.name]] for (slot in c('feature.loadings', 'feature.loadings.projected')) { if (!IsMatrixEmpty(x = slot(object = reduc, name = slot))) { rownames(x = slot(object = reduc, name = slot)) <- gsub( pattern = '_', replacement = '-', x = rownames(x = slot(object = reduc, name = slot)) ) rownames(x = slot(object = reduc, name = slot)) <- gsub( pattern = '_', replacement = '-', x = rownames(x = slot(object = reduc, name = slot)), fixed = TRUE ) } } suppressWarnings( expr = object[[reduc.name]] <- reduc, classes = 'validationWarning' ) } # Update Assays, DimReducs, and Graphs for (x in names(x = object)) { message("Updating slots in ", x) xobj <- object[[x]] xobj <- suppressWarnings( expr = UpdateSlots(object = xobj), classes = 'validationWarning' ) if (inherits(x = xobj, what = "SCTAssay")){ sctmodels <- names(x = slot(object = xobj, name = "SCTModel.list")) for (sctmodel in sctmodels){ median_umi <- tryCatch( expr = slot(object = xobj@SCTModel.list[[sctmodel]], name = "median_umi"), error = function(...) { return(0) } ) xobj@SCTModel.list[[sctmodel]]@median_umi <- median_umi } } if (inherits(x = xobj, what = 'DimReduc')) { if (any(sapply(X = c('tsne', 'umap'), FUN = grepl, x = tolower(x = x)))) { message("Setting ", x, " DimReduc to global") slot(object = xobj, name = 'global') <- TRUE } } else if (inherits(x = xobj, what = 'Graph')) { graph.assay <- unlist(x = strsplit(x = x, split = '_'))[1] if (graph.assay %in% Assays(object = object)) { message("Setting default assay of ", x, " to ", graph.assay) suppressWarnings( expr = DefaultAssay(object = xobj) <- graph.assay, classes = 'validationWarning' ) } else { message( "Cannot find ", graph.assay, " in the object, setting default assay of ", x, " to ", DefaultAssay(object = object) ) suppressWarnings( expr = DefaultAssay(object = xobj) <- DefaultAssay(object = object), classes = 'validationWarning' ) } } suppressWarnings( expr = object[[x]] <- xobj, classes = 'validationWarning' ) } # Update SeuratCommands for (cmd in Command(object = object)) { cobj <- Command(object = object, command = cmd) cobj <- UpdateSlots(object = cobj) cmd.assay <- unlist(x = strsplit(x = cmd, split = '\\.')) cmd.assay <- cmd.assay[length(x = cmd.assay)] cmd.assay <- if (cmd.assay %in% Assays(object = object)) { cmd.assay } else if (cmd.assay %in% Reductions(object = object)) { DefaultAssay(object = object[[cmd.assay]]) } else { NULL } if (is.null(x = cmd.assay)) { message("No assay information could be found for ", cmd) } else { message("Setting assay used for ", cmd, " to ", cmd.assay) } slot(object = cobj, name = 'assay.used') <- cmd.assay suppressWarnings( expr = object[[cmd]] <- cobj, classes = 'validationWarning' ) } # Update object version slot(object = object, name = 'version') <- packageVersion(pkg = 'Seurat') } object <- suppressWarnings( expr = UpdateSlots(object = object), classes = 'validationWarning' ) if (package_version(x = slot(object = object, name = 'version')) <= package_version(x = '4.0.0')) { # Transfer the object to the SeuratObject namespace object <- suppressWarnings( expr = UpdateClassPkg( object = object, from = 'Seurat', to = 'SeuratObject' ), classes = 'validationWarning' ) } slot(object = object, name = 'version') <- packageVersion(pkg = 'SeuratObject') options(op) validObject(object = object, complete = TRUE) for (i in names(x = object)) { message( "Validating object structure for ", paste(class(x = object[[i]])[1L], sQuote(x = i)) ) validObject(object = object[[i]]) } message("Object representation is consistent with the most current Seurat version") return(object) } stop( "We are unable to convert Seurat objects less than version 2.X to version 3.X\n", 'Please use devtools::install_version to install Seurat v2.3.4 and update your object to a 2.X object', call. = FALSE ) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for Seurat-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' @rdname AddMetaData #' @export #' @method AddMetaData Seurat #' AddMetaData.Seurat <- .AddMetaData #' @rdname ObjectAccess #' @method Assays Seurat #' @export #' Assays.Seurat <- function(object, slot = deprecated(), ...) { if (is_present(arg = slot)) { .Deprecate( when = '5.0.0', what = 'Assays(slot = )', with = 'LayerData()' ) return(methods::slot(object = object, name = 'assays')[[slot]]) } return(names(x = methods::slot(object = object, name = 'assays'))) } #' @method CastAssay Seurat #' @export #' CastAssay.Seurat <- function(object, to, assay = NULL, layers = NA, ...) { assay <- assay[1L] %||% DefaultAssay(object = object) assay <- arg_match0(arg = assay, values = Assays(object = object)) to <- enquo(arg = to) object[[assay]] <- CastAssay( object = object[[assay]], to = to, layers = layers, ... ) validObject(object = object) return(object) } #' @method Cells Seurat #' @export #' Cells.Seurat <- function(x, assay = NULL, ...) { assay <- assay[1L] %||% DefaultAssay(object = x) if (is.na(x = assay)) { return(colnames(x = x)) } assay <- tryCatch( expr = match.arg(arg = assay, choices = Assays(object = x)), error = function(e) { return(NULL) } ) return(Cells(x = x[[assay]], ...)) } #' @param command Name of the command to pull, pass \code{NULL} to get the #' names of all commands run #' @param value Name of the parameter to pull the value for #' #' @rdname Command #' @export #' @method Command Seurat #' Command.Seurat <- function(object, command = NULL, value = NULL, ...) { CheckDots(...) object <- UpdateSlots(object = object) commands <- slot(object = object, name = "commands") if (is.null(x = command)) { return(names(x = commands)) } if (is.null(x = commands[[command]])) { stop(command, " has not been run or is not a valid command.") } command <- commands[[command]] if (is.null(x = value)) { return(command) } params <- slot(object = command, name = "params") if (!value %in% names(x = params)) { stop(value, " is not a valid parameter for ", slot(object = command, name = "name")) } return(params[[value]]) } # @param row.names When \code{counts} is a \code{data.frame} or # \code{data.frame}-derived object: an optional vector of feature names to be # used # #' @rdname CreateSeuratObject #' @method CreateSeuratObject default #' @export #' CreateSeuratObject.default <- function( counts, assay = 'RNA', names.field = 1L, names.delim = '_', meta.data = NULL, project = 'SeuratProject', min.cells = 0, min.features = 0, ... ) { assay.version <- getOption(x = 'Seurat.object.assay.version', default = 'v5') if (.GetSeuratCompat() < '5.0.0') { assay.version <- 'v3' } else if (!inherits(counts, what = c('matrix', 'dgCMatrix')) && assay.version == 'v3') { message( "Counts matrix provided is not sparse; vreating v5 assay in Seurat object" ) assay.version <- 'v5' } assay.data <- if (tolower(x = assay.version) == 'v3') { assay.data <- CreateAssayObject( counts = counts, min.cells = min.cells, min.features = min.features, ... ) } else { CreateAssay5Object( counts = counts, min.cells = min.cells, min.features = min.features, ... ) } return(CreateSeuratObject( counts = assay.data, assay = assay, names.field = names.field, names.delim = names.delim, meta.data = meta.data, project = project )) } #' @rdname CreateSeuratObject #' @method CreateSeuratObject Assay #' @export #' CreateSeuratObject.Assay <- function( counts, assay = 'RNA', names.field = 1L, names.delim = '_', meta.data = NULL, project = 'SeuratProject', ... ) { # Check the assay key if (!isTRUE(x = nzchar(x = Key(object = counts)))) { Key(object = counts) <- Key(object = tolower(x = assay), quiet = TRUE) } # Assemble the assay list assay.list <- list(counts) names(x = assay.list) <- assay # Create identity classes idents <- factor(x = unlist(x = lapply( X = colnames(x = counts), FUN = ExtractField, field = names.field, delim = names.delim ))) if (any(is.na(x = idents))) { warn( "Input parameters result in NA values for initial cell identities. Setting all initial idents to the project name", call. = FALSE, immediate. = TRUE ) idents <- factor(x = rep_len(x = project, length.out = ncol(x = counts))) } nidents <- length(x = levels(x = idents)) if (nidents > 100L || nidents == 0L || nidents == length(x = idents)) { idents <- factor(x = rep_len(x = project, length.out = ncol(x = counts))) } names(x = idents) <- colnames(x = counts) # Initialize meta data meta.init <- EmptyDF(n = ncol(x = counts)) row.names(x = meta.init) <- colnames(x = counts) # Create the object op <- options(Seurat.object.validate = FALSE) on.exit(expr = options(op), add = TRUE) object <- suppressWarnings(expr = new( Class = 'Seurat', assays = assay.list, meta.data = meta.init, active.assay = assay, active.ident = idents, graphs = list(), neighbors = list(), reductions = list(), images = list(), project.name = project, misc = list(), version = packageVersion(pkg = 'SeuratObject'), commands = list(), tools = list() )) options(op) object[['orig.ident']] <- idents # Calculate nCount and nFeature calcN_option <- getOption( x = 'Seurat.object.assay.calcn', default = Seurat.options$Seurat.object.assay.calcn ) calcN_option <- calcN_option %||% TRUE if (isTRUE(x = calcN_option)) { ncalc <- CalcN(object = counts) if (!is.null(x = ncalc)) { names(x = ncalc) <- paste(names(x = ncalc), assay, sep = '_') object[[]] <- ncalc } } # Add provided meta data if (!is.null(x = meta.data)) { tryCatch( expr = object[[]] <- meta.data, error = function(e) { warning(e$message, call. = FALSE, immediate. = TRUE) } ) } # Validate and return validObject(object = object) return(object) } #' @method CreateSeuratObject StdAssay #' @export #' CreateSeuratObject.StdAssay <- CreateSeuratObject.Assay #' @rdname CreateSeuratObject #' @method CreateSeuratObject Assay5 #' @export #' CreateSeuratObject.Assay5 <- CreateSeuratObject.StdAssay #' @rdname DefaultAssay #' @export #' @method DefaultAssay Seurat #' #' @examples #' # Get current default assay #' DefaultAssay(object = pbmc_small) #' DefaultAssay.Seurat <- function(object, ...) { CheckDots(...) default <- slot(object = object, name = 'active.assay') if (!length(x = default)) { default <- NULL } return(default) } #' @rdname DefaultAssay #' @export #' @method DefaultAssay<- Seurat #' #' @examples #' # Create dummy new assay to demo switching default assays #' new.assay <- pbmc_small[["RNA"]] #' Key(object = new.assay) <- "RNA2_" #' pbmc_small[["RNA2"]] <- new.assay #' # switch default assay to RNA2 #' DefaultAssay(object = pbmc_small) <- "RNA2" #' DefaultAssay(object = pbmc_small) #' "DefaultAssay<-.Seurat" <- function(object, ..., value) { CheckDots(...) value <- value[1L] value <- match.arg(arg = value, choices = Assays(object = object)) slot(object = object, name = 'active.assay') <- value return(object) } #' @param assay Name of assay to get or set default \code{\link{FOV}} for; #' pass \code{NA} to get or set the global default \code{\link{FOV}} #' #' @rdname DefaultFOV #' @method DefaultFOV Seurat #' @export #' DefaultFOV.Seurat <- function(object, assay = NULL, ...) { assay <- assay[1L] %||% DefaultAssay(object = object) fovs <- .FilterObjects(object = object, classes.keep = 'FOV') if (is.na(x = assay)) { return(fovs[1L]) } assay <- match.arg(arg = assay, choices = Assays(object = object)) assay.fovs <- Filter( f = function(x) { return(DefaultAssay(object = object[[x]]) == assay) }, x = fovs ) if (!length(x = assay.fovs)) { warning( "No FOV associated with assay '", assay, "', using global default FOV", call. = FALSE, immediate. = TRUE ) assay.fovs <- fovs[1L] } return(assay.fovs[1L]) } #' @rdname DefaultFOV #' @method DefaultFOV<- Seurat #' @export #' "DefaultFOV<-.Seurat" <- function(object, assay = NA, ..., value) { assay <- assay[1L] %||% DefaultAssay(object = object) fovs <- .FilterObjects(object = object, classes.keep = 'FOV') value <- match.arg(arg = value, choices = fovs) if (!is.na(x = assay)) { assay <- match.arg(arg = assay, choices = Assays(object = object)) if (DefaultAssay(object = object[[value]]) != assay) { warning( "FOV '", value, "' currently associated with assay '", DefaultAssay(object = object[[value]]), "', changing to '", assay, "'", call. = FALSE, immediate. = TRUE ) DefaultAssay(object = object[[value]]) <- assay } fovs <- Filter( f = function(x) { return(DefaultAssay(object = object[[x]]) == assay) }, x = fovs ) } fidx <- which(x = fovs == value) forder <- c(fidx, setdiff(x = seq_along(along.with = fovs), y = fidx)) fovs <- fovs[forder] iidx <- seq_along(along.with = Images(object = object)) midx <- MatchCells(new = Images(object = object), orig = fovs, ordered = TRUE) iidx[sort(x = midx)] <- midx slot(object = object, name = 'images') <- slot( object = object, name = 'images' )[iidx] return(object) } #' @param reduction Name of reduction to pull cell embeddings for #' #' @rdname Embeddings #' @export #' @method Embeddings Seurat #' #' @examples #' # Get the embeddings from a specific DimReduc in a Seurat object #' Embeddings(object = pbmc_small, reduction = "pca")[1:5, 1:5] #' Embeddings.Seurat <- function(object, reduction = 'pca', ...) { return(Embeddings(object = object[[reduction]], ...)) } #' @method Features Seurat #' @export #' Features.Seurat <- function(x, assay = NULL, ...) { assay <- assay[1L] %||% DefaultAssay(object = x) assay <- match.arg(arg = assay, choices = Assays(object = x)) return(Features(x = x[[assay]], ...)) } #' @param vars List of all variables to fetch, use keyword \dQuote{ident} to #' pull identity classes #' @param cells Cells to collect data for (default is all cells) #' @param layer Layer to pull feature data for #' @param clean Remove cells that are missing data; choose from: #' \itemize{ #' \item \dQuote{\code{all}}: consider all columns for cleaning #' \item \dQuote{\code{ident}}: consider all columns except the identity #' class for cleaning #' \item \dQuote{\code{project}}: consider all columns except the identity #' class for cleaning; fill missing identity values with the object's project #' \item \dQuote{\code{none}}: do not clean #' } #' Passing \code{TRUE} is a shortcut for \dQuote{\code{ident}}; passing #' \code{FALSE} is a shortcut for \dQuote{\code{none}} #' @param slot Deprecated in favor of \code{layer} #' #' @return A data frame with cells as rows and cellular data as columns #' #' @rdname FetchData #' @method FetchData Seurat #' @export #' #' @concept data-access #' #' @examples #' pc1 <- FetchData(object = pbmc_small, vars = 'PC_1') #' head(x = pc1) #' head(x = FetchData(object = pbmc_small, vars = c('groups', 'ident'))) #' FetchData.Seurat <- function( object, vars, cells = NULL, layer = NULL, clean = TRUE, slot = deprecated(), ... ) { if (is_present(arg = slot)) { .Deprecate( when = '5.0.0', what = 'FetchData(slot = )', with = 'FetchData(layer = )' ) layer <- layer %||% slot } object <- UpdateSlots(object = object) if (isTRUE(x = clean)) { clean <- 'ident' } else if (isFALSE(x = clean)) { clean <- 'none' } clean <- arg_match0(arg = clean, values = c('all', 'ident', 'none', 'project')) # Find cells to use cells <- cells %||% colnames(x = object) if (is.numeric(x = cells)) { cells <- colnames(x = object)[cells] } if (is.null(x = vars)) { return(data.frame(row.names = cells)) } data.fetched <- EmptyDF(n = length(x = cells)) row.names(x = data.fetched) <- cells # Pull vars from object metadata meta.vars <- intersect(x = vars, y = names(x = object[[]])) meta.vars <- setdiff(x = meta.vars, y = names(x = data.fetched)) if (length(x = meta.vars)) { meta.default <- intersect(x = meta.vars, y = rownames(x = object)) if (length(x = meta.default)) { warn(message = paste0( "The following variables were found in both object meta data and the default assay: ", paste0(meta.default, collapse = ', '), "\nReturning meta data; if you want the feature, please use the assay's key (eg. ", paste0(Key(object = object)[DefaultAssay(object = object)], meta.default[1L]), ")" )) } meta.pull <- object[[meta.vars]] cells.meta <- row.names(x = meta.pull) cells.order <- MatchCells(new = cells.meta, orig = cells, ordered = TRUE) cells.meta <- cells.meta[cells.order] data.fetched[cells.meta, meta.vars] <- meta.pull[cells.meta, , drop = FALSE] } # Find all vars that are keyed keyed.vars <- sapply( X = Keys(object = object), FUN = function(key) { if (!length(x = key) || !nzchar(x = key)) { return(character(length = 0L)) } return(grep(pattern = paste0('^', key), x = setdiff(vars, meta.vars), value = TRUE)) }, simplify = FALSE, USE.NAMES = TRUE ) keyed.vars <- Filter(f = length, x = keyed.vars) # Check spatial keyed vars ret.spatial2 <- vapply( X = names(x = keyed.vars), FUN = function(x) { return(inherits(x = object[[x]], what = 'FOV')) }, FUN.VALUE = logical(length = 1L), USE.NAMES = FALSE ) if (any(ret.spatial2)) { abort(message = "Spatial coordinates are no longer fetchable with FetchData") } # Find all keyed.vars data.keyed <- lapply( X = names(x = keyed.vars), FUN = function(x) { data.return <- switch( EXPR = x, meta.data = { md <- gsub(pattern = '^md', replacement = '', x = keyed.vars[[x]]) df <- object[[md]][cells, , drop = FALSE] names(x = df) <- paste0('md_', names(x = df)) df }, tryCatch( expr = FetchData( object = object[[x]], vars = keyed.vars[[x]], cells = cells, layer = layer, ... ), varsNotFoundError = function(...) { warn(message = paste0( 'The following keyed vars could not be found in object ', sQuote(x = x), ':', paste(keyed.vars[[x]], collapse = ', '), '\nAttempting to pull from other locations' )) return(NULL) } ) ) return(data.return) } ) for (i in seq_along(along.with = data.keyed)) { df <- data.keyed[[i]] data.fetched[row.names(x = df), names(x = df)] <- df } # Pull vars from the default assay default.vars <- intersect(x = vars, y = rownames(x = object)) default.vars <- setdiff(x = default.vars, y = names(x = data.fetched)) if (length(x = default.vars)) { df <- FetchData( object = object[[DefaultAssay(object = object)]], vars = default.vars, cells = cells, layer = layer, ... ) data.fetched[row.names(x = df), names(x = df)] <- df } # Pull identities if ('ident' %in% vars && !'ident' %in% names(x = object[[]])) { data.fetched[cells, 'ident'] <- Idents(object = object)[cells] } # Try to find ambiguous vars vars.missing <- setdiff(x = vars, y = names(x = data.fetched)) if (length(x = vars.missing)) { # Search for vars in alternate assays # Create a list to hold vars and the alternate assays they're found in vars.alt <- vector(mode = 'list', length = length(x = vars.missing)) names(x = vars.alt) <- vars.missing # Search through features in alternate assays to see if # they contain our missing vars for (assay in Assays(object = object)) { vars.assay <- Filter( f = function(x) { return(x %in% Features(x = object, assay = assay, layer = layer)) }, x = vars.missing ) # Add the alternate assay to our holding list for our found vars for (var in vars.assay) { vars.alt[[var]] <- append(x = vars.alt[[var]], values = assay) } } # Vars found in multiple alternative assays are truly ambiguous, will not pull vars.many <- names(x = Filter( f = function(x) { return(length(x = x) > 1) }, x = vars.alt )) if (length(x = vars.many)) { warn(message = paste( "Found the following features in more than one assay, excluding the default.", "We will not include these in the final data frame:", paste(vars.many, collapse = ', ') )) } # Missing vars are either ambiguous or not found in exactly one assay vars.missing <- names(x = Filter( f = function(x) { return(length(x = x) != 1) }, x = vars.alt )) # Pull vars found in only one alternative assay # Key this var to highlight that it was found in an alternate assay vars.alt <- Filter( f = function(x) { return(length(x = x) == 1) }, x = vars.alt ) for (var in names(x = vars.alt)) { assay <- vars.alt[[var]] warn(message = paste( 'Could not find', var, 'in the default search locations, found in', sQuote(x = assay), 'assay instead' )) keyed.var <- paste0(Key(object = object[[assay]]), var) vars[vars == var] <- keyed.var df <- FetchData( object = object[[assay]], vars = keyed.var, cells = cells, layer = layer ) data.fetched[row.names(x = df), names(x = df)] <- df } } # Name the vars not found in a warning (or error if no vars found) # `m2` is an additional message if we're missing more than 10 vars m2 <- if (length(x = vars.missing) > 10) { paste(' (10 out of', length(x = vars.missing), 'shown)') } else { '' } if (length(x = vars.missing) == length(x = vars)) { abort( message = paste0( "None of the requested variables were found", m2, ': ', paste(head(x = vars.missing, n = 10L), collapse = ', ') ), class = 'varsNotFoundError' ) } else if (length(x = vars.missing)) { warn(message = paste0( "The following requested variables were not found", m2, ': ', paste(head(x = vars.missing, n = 10L), collapse = ', ') )) } .FilterData <- function(df) { return(which(x = apply(X = df, MARGIN = 1L, FUN = \(x) all(is.na(x = x))))) } # Clean the fetched data data.fetched <- switch( EXPR = clean, all = { # Clean all vars no.data <- .FilterData(df = data.fetched) if (length(x = no.data)) { warn(message = paste( "Removing", length(x = no.data), "cells missing data for vars requested" )) data.fetched[-no.data, , drop = FALSE] } else { data.fetched } }, ident = { # Clean all vars except ident cols.clean <- names(x = data.fetched) if (ncol(x = data.fetched) > 2L && !'ident' %in% names(x = object[[]])) { cols.clean <- setdiff(x = cols.clean, y = 'ident') } no.data <- .FilterData(df = data.fetched[, cols.clean, drop = FALSE]) if (length(x = no.data)) { warn(message = paste( "Removing", length(x = no.data), "cells missing data for vars requested" )) data.fetched[-no.data, , drop = FALSE] } else { data.fetched } }, project = { # Clean all vars except ident cols.clean <- names(x = data.fetched) if (ncol(x = data.fetched) > 2L && !'ident' %in% names(x = object[[]])) { cols.clean <- setdiff(x = cols.clean, y = 'ident') } no.data <- .FilterData(df = data.fetched[, cols.clean, drop = FALSE]) if (length(x = no.data)) { warn(message = paste( "Removing", length(x = no.data), "cells missing data for vars requested" )) data.fetched <- data.fetched[-no.data, , drop = FALSE] } # When all idents are `NA`, set to Project(object) if ('ident' %in% names(x = data.fetched) && !'ident' %in% names(x = object[[]])) { if (all(is.na(x = data.fetched$ident))) { warn(message = paste( "None of the cells requested have an identity class, returning", sQuote(x = Project(object = object)), "instead" )) data.fetched$ident <- Project(object = object) } } data.fetched }, # Don't clean vars data.fetched ) vars.return <- intersect(x = vars, y = names(x = data.fetched)) data.fetched <- data.fetched[, vars.return, drop = FALSE] # data.order <- na.omit(object = pmatch( # x = vars, # table = names(x = data.fetched) # )) # if (length(x = data.order) > 1) { # data.fetched <- data.fetched[, data.order] # } # colnames(x = data.fetched) <- vars[vars %in% fetched] return(data.fetched) } #' @param assay Specific assay to get data from or set data for; #' defaults to the \link[=DefaultAssay]{default assay} #' #' @rdname AssayData #' @export #' @method GetAssayData Seurat #' #' @order 3 #' #' @examples #' # Get assay data from the default assay in a Seurat object #' GetAssayData(object = pbmc_small, layer = "data")[1:5,1:5] #' GetAssayData.Seurat <- function( object, assay = NULL, layer = NULL, slot = deprecated(), ... ) { CheckDots(...) if (is_present(arg = slot)) { .Deprecate( when = '5.0.0', what = 'GetAssayData(slot = )', with = 'GetAssayData(layer = )' ) layer <- slot } object <- UpdateSlots(object = object) assay <- assay %||% DefaultAssay(object = object) assay <- arg_match(arg = assay, values = Assays(object = object)) return(GetAssayData(object = object[[assay]], layer = layer)) } #' @param image Name of \code{SpatialImage} object to pull image data for; if #' \code{NULL}, will attempt to select an image automatically #' #' @rdname GetImage #' @method GetImage Seurat #' @export #' GetImage.Seurat <- function( object, mode = c('grob', 'raster', 'plotly', 'raw'), image = NULL, ... ) { mode <- match.arg(arg = mode) image <- image %||% DefaultImage(object = object) if (is.null(x = image)) { stop("No images present in this Seurat object", call. = FALSE) } return(GetImage(object = object[[image]], mode = mode, ...)) } #' @param image Name of \code{SpatialImage} object to get coordinates for; if #' \code{NULL}, will attempt to select an image automatically #' #' @rdname GetTissueCoordinates #' @method GetTissueCoordinates Seurat #' @export #' GetTissueCoordinates.Seurat <- function(object, image = NULL, ...) { image <- image %||% DefaultImage(object = object) if (is.null(x = image)) { stop("No images present in this Seurat object", call. = FALSE) } return(GetTissueCoordinates(object = object[[image]], ...)) } #' @param assay Name of assay to pull highly variable feature information for #' #' @importFrom tools file_path_sans_ext #' #' @rdname VariableFeatures #' @export #' @method HVFInfo Seurat #' #' @order 6 #' #' @examples #' # Get the HVF info from a specific Assay in a Seurat object #' HVFInfo(object = pbmc_small, assay = "RNA")[1:5, ] #' HVFInfo.Seurat <- function( object, method = NULL, status = FALSE, assay = NULL, selection.method = deprecated(), ... ) { CheckDots(...) if (is_present(arg = selection.method)) { .Deprecate( when = '5.0.0', what = 'HVFInfo(selection.method = )', with = 'HVFInfo(method = )' ) method <- selection.method } object <- UpdateSlots(object = object) assay <- assay %||% DefaultAssay(object = object) if (is.null(x = method)) { cmds <- apply( X = expand.grid( c('FindVariableFeatures', 'SCTransform'), .FilterObjects(object = object, classes.keep = c('Assay', 'Assay5')) ), MARGIN = 1, FUN = paste, collapse = '.' ) find.command <- Command(object = object)[Command(object = object) %in% cmds] if (length(x = find.command) < 1) { abort(message = "Please run either 'FindVariableFeatures' or 'SCTransform'") } find.command <- find.command[length(x = find.command)] test.command <- paste(file_path_sans_ext(x = find.command), assay, sep = '.') find.command <- ifelse( test = test.command %in% Command(object = object), yes = test.command, no = find.command ) method <- switch( EXPR = file_path_sans_ext(x = find.command), 'FindVariableFeatures' = Command( object = object, command = find.command, value = 'selection.method' ), 'SCTransform' = 'sct', stop("Unknown command for finding variable features: '", find.command, "'", call. = FALSE) ) } return(HVFInfo( object = object[[assay]], method = method, status = status )) } #' @rdname Idents #' @export #' @method Idents Seurat #' Idents.Seurat <- function(object, ...) { CheckDots(...) # object <- UpdateSlots(object = object) return(slot(object = object, name = 'active.ident')) } #' @param cells Set cell identities for specific cells #' @param drop Drop unused levels #' @param replace Replace identities for unset cells with \code{NA} #' #' @rdname Idents #' @export #' @method Idents<- Seurat #' "Idents<-.Seurat" <- function( object, cells = NULL, drop = FALSE, replace = FALSE, ..., value ) { CheckDots(...) object <- UpdateSlots(object = object) if (!(is.factor(x = value) || is.atomic(x = value))) { abort(message = "'value' must be a factor or vector") } cells <- cells %||% names(x = value) %||% colnames(x = object) if (is.numeric(x = cells)) { cells <- colnames(x = object)[cells] } cells <- intersect(x = cells, y = colnames(x = object)) # cells <- match(x = cells, table = colnames(x = object)) if (!length(x = cells)) { warn(message = 'Cannot find cells provided') return(object) } idents.new <- if (length(x = value) == 1 && value %in% names(x = object[[]])) { # unlist(x = object[[value]], use.names = FALSE)[cells] object[[value, drop = TRUE]][cells] } else { if (is.list(x = value)) { value <- unlist(x = value, use.names = FALSE) } rep_len(x = value, length.out = length(x = cells)) } new.levels <- if (is.factor(x = idents.new)) { levels(x = idents.new) } else { unique(x = idents.new) } levels <- union(x = new.levels, y = levels(x = object)) idents.new <- as.vector(x = idents.new) idents <- if (isTRUE(x = replace)) { rep_len(x = NA_character_, length.out = ncol(x = object)) } else { as.vector(x = Idents(object = object)) } names(x = idents) <- colnames(x = object) idents[cells] <- idents.new idents[is.na(x = idents)] <- 'NA' levels <- intersect(x = levels, y = unique(x = idents)) names(x = idents) <- colnames(x = object) missing.cells <- which(x = is.na(x = names(x = idents))) if (length(x = missing.cells) > 0) { idents <- idents[-missing.cells] } idents <- factor(x = idents, levels = levels) slot(object = object, name = 'active.ident') <- idents if (isTRUE(x = drop)) { object <- droplevels(x = object) } return(object) } #' @param assay Name of assay to split layers #' #' @rdname SplitLayers #' @method JoinLayers Seurat #' @export #' JoinLayers.Seurat <- function( object, assay = NULL, layers = NULL, new = NULL, ... ) { assay <- assay %||% DefaultAssay(object) object[[assay]] <- JoinLayers( object = object[[assay]], layers = layers, new = new, ... ) return(object) } #' @rdname Key #' @export #' @method Key Seurat #' #' @examples #' # Show all keys associated with a Seurat object #' Key(object = pbmc_small) #' Keys(object = pbmc_small) #' Key.Seurat <- function(object, ...) { CheckDots(...) object <- UpdateSlots(object = object) return(c( meta.data = Key(object = 'md', quiet = TRUE), vapply( X = .FilterObjects( object = object, classes.keep = c('Assay', 'SpatialImage', 'KeyMixin') ), FUN = function(x) { return(Key(object = object[[x]])) }, FUN.VALUE = character(length = 1L), USE.NAMES = TRUE ) )) } #' @rdname Key #' @export #' @method Keys Seurat #' Keys.Seurat <- Key.Seurat #' @param assay Name of assay to fetch layer data from or assign layer data to #' #' @rdname Layers #' @method LayerData Seurat #' @export #' LayerData.Seurat <- function( object, layer = NULL, assay = NULL, slot = deprecated(), ... ) { if (is_present(arg = slot)) { deprecate_stop( when = "5.0.0", what = "LayerData(slot = )", with = "LayerData(layer = )" ) } assay <- assay %||% DefaultAssay(object = object) assay <- arg_match(arg = assay, values = Assays(object = object)) return(LayerData(object = object[[assay]], layer = layer, ...)) } #' @rdname Layers #' @method LayerData<- Seurat #' @export #' "LayerData<-.Seurat" <- function(object, layer, assay = NULL, ..., value) { assay <- assay %||% DefaultAssay(object = object) assay <- arg_match(arg = assay, values = Assays(object = object)) LayerData(object = object[[assay]], layer = layer, ...) <- value return(object) } #' @rdname Layers #' @method Layers Seurat #' @export #' Layers.Seurat <- function(object, search = NA, assay = NULL, ...) { assay <- assay %||% DefaultAssay(object = object) assay <- arg_match(arg = assay, values = Assays(object = object)) return(Layers(object = object[[assay]], search = search, ...)) } #' @param reduction Name of reduction to pull feature loadings for #' #' @rdname Loadings #' @export #' @method Loadings Seurat #' #' @examples #' # Get the feature loadings for a specified DimReduc in a Seurat object #' Loadings(object = pbmc_small, reduction = "pca")[1:5,1:5] #' Loadings.Seurat <- function(object, reduction = 'pca', projected = FALSE, ...) { object <- UpdateSlots(object = object) return(Loadings(object = object[[reduction]], projected = projected, ...)) } #' @rdname Misc #' @export #' @method Misc Seurat #' #' @examples #' # Get the misc info #' Misc(object = pbmc_small, slot = "example") #' Misc.Seurat <- .Misc #' @rdname Misc #' @export #' @method Misc<- Seurat #' #' @examples #'# Add misc info #' Misc(object = pbmc_small, slot = "example") <- "testing_misc" #' "Misc<-.Seurat" <- `.Misc<-` #' @rdname Project #' @export #' @method Project Seurat #' Project.Seurat <- function(object, ...) { CheckDots(...) object <- UpdateSlots(object = object) return(slot(object = object, name = 'project.name')) } #' @rdname Project #' @export #' @method Project<- Seurat #' "Project<-.Seurat" <- function(object, ..., value) { CheckDots(...) object <- UpdateSlots(object = object) slot(object = object, name = 'project.name') <- as.character(x = value) return(object) } #' @param reverse Reverse ordering #' @param afxn Function to evaluate each identity class based on; default is #' \code{\link[base]{mean}} #' @param reorder.numeric Rename all identity classes to be increasing numbers #' starting from 1 (default is FALSE) #' #' @rdname Idents #' @export #' @method ReorderIdent Seurat #' ReorderIdent.Seurat <- function( object, var, reverse = FALSE, afxn = mean, reorder.numeric = FALSE, ... ) { object <- UpdateSlots(object = object) data.use <- FetchData(object = object, vars = var, ...)[, 1] rfxn <- ifelse( test = reverse, yes = function(x) { return(max(x) + 1 - x) }, no = identity ) new.levels <- names(x = rfxn(x = sort(x = tapply( X = data.use, INDEX = Idents(object = object), FUN = afxn )))) new.idents <- factor( x = Idents(object = object), levels = new.levels, ordered = TRUE ) if (reorder.numeric) { new.idents <- rfxn(x = rank(x = tapply( X = data.use, INDEX = as.numeric(x = new.idents), FUN = mean )))[as.numeric(x = new.idents)] new.idents <- factor( x = new.idents, levels = 1:length(x = new.idents), ordered = TRUE ) } Idents(object = object) <- new.idents return(object) } #' @param add.cell.id prefix to add cell names #' @param for.merge Deprecated #' #' @details #' If \code{add.cell.id} is set a prefix is added to existing cell names. If #' \code{new.names} is set these will be used to replace existing names. #' #' @rdname RenameCells #' @export #' @method RenameCells Seurat #' #' @examples #' # Rename cells in a Seurat object #' head(x = colnames(x = pbmc_small)) #' pbmc_small <- RenameCells(object = pbmc_small, add.cell.id = "A") #' head(x = colnames(x = pbmc_small)) #' RenameCells.Seurat <- function( object, add.cell.id = missing_arg(), new.names = missing_arg(), for.merge = deprecated(), ... ) { CheckDots(...) object <- UpdateSlots(object = object) working.cells <- Cells(x = object) if (is_present(arg = for.merge)) { .Deprecate(when = '5.0.0', what = 'RenameCells(for.merge = )') } if (is_missing(x = add.cell.id) && is_missing(x = new.names)) { abort(message = "One of 'add.cell.id' and 'new.names' must be set") } if (!is_missing(x = add.cell.id) && !is_missing(x = new.names)) { abort(message = "Only one of 'add.cell.id' and 'new.names' may be set") } if (!missing(x = add.cell.id)) { new.cell.names <- paste(add.cell.id, working.cells, sep = "_") } else { if (length(x = new.names) == length(x = working.cells)) { new.cell.names <- new.names } else { abort(message = paste0( "the length of 'new.names' (", length(x = new.names), ") must be the same as the number of cells (", length(x = working.cells), ")" )) } } old.names <- colnames(x = object) new.cell.names.global <- old.names new.cell.names.global[match(x = working.cells, table = old.names)] <- new.cell.names new.cell.names <- new.cell.names.global # rename the cell-level metadata first to rename colname() old.meta.data <- object[[]] row.names(x = old.meta.data) <- new.cell.names slot(object = object, name = "meta.data") <- old.meta.data # rename the active.idents old.ids <- Idents(object = object) names(x = old.ids) <- new.cell.names Idents(object = object) <- old.ids names(x = new.cell.names) <- old.names # rename in the assay objects assays <- .FilterObjects(object = object, classes.keep = 'Assay') for (i in assays) { slot(object = object, name = "assays")[[i]] <- RenameCells( object = object[[i]], new.names = new.cell.names[colnames(x = object[[i]])] ) } # rename in the assay5 objects assays5 <- .FilterObjects(object = object, classes.keep = 'Assay5') for (i in assays5) { slot(object = object, name = "assays")[[i]] <- RenameCells( object = object[[i]], new.names = new.cell.names[colnames(x = object[[i]])] ) } # rename in the DimReduc objects dimreducs <- .FilterObjects(object = object, classes.keep = 'DimReduc') for (i in dimreducs) { slot(object = object, name = "reductions")[[i]] <- RenameCells( object = object[[i]], new.names = new.cell.names[Cells(x = object[[i]])] ) } # rename the graphs graphs <- .FilterObjects(object = object, classes.keep = "Graph") for (g in graphs) { graph.g <- object[[g]] rownames(graph.g) <- colnames(graph.g) <- new.cell.names[colnames(x = graph.g)] slot(object = object, name = "graphs")[[g]] <- graph.g } # Rename the images for (i in Images(object = object)) { slot(object = object, name = "images")[[i]] <- RenameCells( object = object[[i]], new.names = unname( obj = new.cell.names[Cells(x = object[[i]], boundary = NA)] ) ) } # Rename the Neighbor for (i in Neighbors(object = object)) { slot(object = object, name = "neighbors")[[i]] <- RenameCells( object = object[[i]], old.names = Cells(x = object[[i]]), new.names = new.cell.names[Cells(x = object[[i]])] ) } validObject(object) return(object) } #' @rdname Idents #' @export #' @method RenameIdents Seurat #' RenameIdents.Seurat <- function(object, ...) { ident.pairs <- tryCatch( expr = as.list(x = ...), error = function(e) { return(list(...)) } ) if (is.null(x = names(x = ident.pairs))) { stop("All arguments must be named with the old identity class") } if (!all(sapply(X = ident.pairs, FUN = length) == 1)) { stop("Can only rename identity classes to one value") } if (!any(names(x = ident.pairs) %in% levels(x = object))) { stop("Cannot find any of the provided identities") } cells.idents <- CellsByIdentities(object = object) for (i in rev(x = names(x = ident.pairs))) { if (!i %in% names(x = cells.idents)) { warning("Cannot find identity ", i, call. = FALSE, immediate. = TRUE) next } Idents(object = object, cells = cells.idents[[i]]) <- ident.pairs[[i]] } return(object) } #' @rdname AssayData #' @export #' @method SetAssayData Seurat #' #' @order 4 #' #' @examples #' # Set an Assay layer through the Seurat object #' count.data <- GetAssayData(object = pbmc_small[["RNA"]], layer = "counts") #' count.data <- as.matrix(x = count.data + 1) #' new.seurat.object <- SetAssayData( #' object = pbmc_small, #' layer = "counts", #' new.data = count.data, #' assay = "RNA" #' ) #' SetAssayData.Seurat <- function( object, layer = 'data', new.data, slot = deprecated(), assay = NULL, ... ) { CheckDots(...) if (is_present(arg = slot)) { .Deprecate( when = '5.0.0', what = 'SetAssayData(slot = )', with = 'SetAssayData(layer = )' ) layer <- slot } object <- UpdateSlots(object = object) assay <- assay %||% DefaultAssay(object = object) object[[assay]] <- SetAssayData( object = object[[assay]], layer = layer, new.data = new.data, ... ) return(object) } #' @rdname Idents #' @export #' @method SetIdent Seurat #' SetIdent.Seurat <- function(object, cells = NULL, value, ...) { #message( # 'With Seurat 3.X, setting identity classes can be done as follows:\n', # 'Idents(object = ', # deparse(expr = substitute(expr = object)), # if (!is.null(x = cells)) { # paste0(', cells = ', deparse(expr = substitute(expr = cells))) # }, # ') <- ', # deparse(expr = substitute(expr = value)) #) CheckDots(...) object <- UpdateSlots(object = object) Idents(object = object, cells = cells) <- value return(object) } #' @rdname VariableFeatures #' @export #' @method SpatiallyVariableFeatures Seurat #' #' @order 10 #' SpatiallyVariableFeatures.Seurat <- function( object, method = "moransi", assay = NULL, decreasing = TRUE, selection.method = deprecated(), ... ) { CheckDots(...) if (is_present(arg = selection.method)) { .Deprecate( when = '5.0.0', what = 'SpatiallyVariableFeatures(selection.method = )', with = 'SpatiallyVariableFeatures(method = )' ) method <- selection.method } assay <- assay %||% DefaultAssay(object = object) return(SpatiallyVariableFeatures( object = object[[assay]], method = method, decreasing = decreasing )) } #' @param save.name Store current identity information under this name #' #' @rdname Idents #' @export #' @method StashIdent Seurat #' StashIdent.Seurat <- function(object, save.name = 'orig.ident', ...) { deprecate_soft( when = '3.0.0', what = 'StashIdent()', details = paste0( "Please use ", deparse(expr = substitute(expr = object)), '[[', deparse(expr = substitute(expr = save.name)), ']] <- Idents(', deparse(expr = substitute(expr = object)), ')' ) ) CheckDots(...) object <- UpdateSlots(object = object) object[[save.name]] <- Idents(object = object) return(object) } #' @param reduction Name of reduction to use #' #' @rdname Stdev #' @export #' @method Stdev Seurat #' #' @examples #' # Get the standard deviations for each PC from the Seurat object #' Stdev(object = pbmc_small, reduction = "pca") #' Stdev.Seurat <- function(object, reduction = 'pca', ...) { CheckDots(...) return(Stdev(object = object[[reduction]])) } #' @importFrom tools file_path_sans_ext #' #' @rdname VariableFeatures #' @export #' @method SVFInfo Seurat #' #' @order 9 #' SVFInfo.Seurat <- function( object, method = c("markvariogram", "moransi"), status = FALSE, assay = NULL, selection.method = deprecated(), ... ) { CheckDots(...) if (is_present(arg = selection.method)) { .Deprecate( when = '5.0.0', what = 'SVFInfo(selection.method = )', with = 'SVFInfo(method = )' ) method <- selection.method } assay <- assay %||% DefaultAssay(object = object) return(SVFInfo(object = object[[assay]], method = method, status = status)) } #' @param slot Name of tool to pull #' #' @rdname Tool #' @export #' @method Tool Seurat #' Tool.Seurat <- function(object, slot = NULL, ...) { CheckDots(...) object <- UpdateSlots(object = object) if (is.null(x = slot)) { return(names(x = slot(object = object, name = 'tools'))) } return(slot(object = object, name = 'tools')[[slot]]) } #' @rdname Tool #' @export #' @method Tool<- Seurat #' "Tool<-.Seurat" <- function(object, ..., value) { CheckDots(...) object <- UpdateSlots(object = object) calls <- as.character(x = sys.calls()) calls <- lapply( X = strsplit(x = calls, split = '(', fixed = TRUE), FUN = '[', 1 ) tool.call <- min(grep(pattern = 'Tool<-', x = calls)) if (tool.call <= 1) { stop("'Tool<-' cannot be called at the top level", call. = FALSE) } tool.call <- calls[[tool.call - 1]] class.call <- unlist(x = strsplit( x = as.character(x = sys.call())[1], split = '.', fixed = TRUE )) class.call <- class.call[length(x = class.call)] tool.call <- sub( pattern = paste0('\\.', class.call, '$'), replacement = '', x = tool.call, perl = TRUE ) slot(object = object, name = 'tools')[[tool.call]] <- value return(object) } #' @rdname VariableFeatures #' @export #' @method VariableFeatures Seurat #' #' @order 7 #' VariableFeatures.Seurat <- function( object, method = NULL, assay = NULL, nfeatures = NULL, layer = NA, simplify = TRUE, selection.method = deprecated(), ... ) { CheckDots(...) if (is_present(arg = selection.method)) { .Deprecate( when = '5.0.0', what = 'VariableFeatures(selection.method = )', with = 'VariableFeatures(method = )' ) method <- selection.method } assay <- assay %||% DefaultAssay(object = object) return(VariableFeatures( object = object[[assay]], method = method, nfeatures = nfeatures, layer = layer, simplify = simplify, ... )) } #' @rdname VariableFeatures #' @export #' @method VariableFeatures<- Seurat #' #' @order 8 #' "VariableFeatures<-.Seurat" <- function(object, assay = NULL, ..., value) { CheckDots(...) object <- UpdateSlots(object = object) assay <- assay %||% DefaultAssay(object = object) VariableFeatures(object = object[[assay]]) <- value return(object) } #' @param idents A vector of identity classes to keep #' @param slot Slot to pull feature data for #' @param downsample Maximum number of cells per identity class, default is #' \code{Inf}; downsampling will happen after all other operations, including #' inverting the cell selection #' @param seed Random seed for downsampling. If NULL, does not set a seed #' @inheritDotParams CellsByIdentities #' #' @importFrom stats na.omit #' @importFrom rlang is_quosure enquo eval_tidy #' #' @rdname WhichCells #' @export #' @method WhichCells Seurat #' WhichCells.Seurat <- function( object, cells = NULL, idents = NULL, expression, slot = 'data', invert = FALSE, downsample = Inf, seed = 1, ... ) { CheckDots(..., fxns = CellsByIdentities) if (!is.null(x = seed)) { set.seed(seed = seed) } object <- UpdateSlots(object = object) cells <- cells %||% colnames(x = object) if (is.numeric(x = cells)) { cells <- colnames(x = object)[cells] } cell.order <- cells if (!is.null(x = idents)) { if (any(!idents %in% levels(x = Idents(object = object)))) { stop( "Cannot find the following identities in the object: ", paste( idents[!idents %in% levels(x = Idents(object = object))], sep = ', ' ) ) } cells.idents <- unlist(x = lapply( X = idents, FUN = function(i) { cells.use <- which(x = as.vector(x = Idents(object = object)) == i) cells.use <- names(x = Idents(object = object)[cells.use]) return(cells.use) } )) cells <- intersect(x = cells, y = cells.idents) } if (!missing(x = expression)) { objects.use <- .FilterObjects( object = object, classes.keep = c('Assay', 'StdAssay', 'DimReduc', 'SpatialImage') ) object.keys <- sapply( X = objects.use, FUN = function(i) { return(Key(object = object[[i]])) } ) key.pattern <- paste0('^', object.keys, collapse = '|') expr <- if (tryCatch(expr = is_quosure(x = expression), error = function(...) FALSE)) { expression } else if (is.call(x = enquo(arg = expression))) { enquo(arg = expression) } else { parse(text = expression) } expr.char <- suppressWarnings(expr = as.character(x = expr)) expr.char <- unlist(x = lapply(X = expr.char, FUN = strsplit, split = ' ')) expr.char <- gsub( pattern = '(', replacement = '', x = expr.char, fixed = TRUE ) expr.char <- gsub( pattern = '`', replacement = '', x = expr.char ) vars.use <- which( x = expr.char %in% rownames(x = object) | expr.char %in% colnames(x = object[[]]) | grepl(pattern = key.pattern, x = expr.char, perl = TRUE) ) data.subset <- FetchData( object = object, vars = unique(x = expr.char[vars.use]), cells = cells, layer = slot ) cells <- rownames(x = data.subset)[eval_tidy(expr = expr, data = data.subset)] } if (isTRUE(x = invert)) { cell.order <- colnames(x = object) cells <- colnames(x = object)[!colnames(x = object) %in% cells] } # only perform downsampling when "downsample" is smaller than the number of cells if(downsample <= length(cells)){ cells <- CellsByIdentities(object = object, cells = cells, ...) cells <- lapply( X = cells, FUN = function(x) { if (length(x = x) > downsample) { x <- sample(x = x, size = downsample, replace = FALSE) } return(x) } ) cells <- as.character(x = na.omit(object = unlist(x = cells, use.names = FALSE))) } cells <- cells[na.omit(object = match(x = cell.order, table = cells))] return(cells) } #' @rdname Version #' @method Version Seurat #' @export #' Version.Seurat <- function(object, ...) { CheckDots(...) return(slot(object = object, name = 'version')) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for R-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' Dollar-sign Autocompletion #' #' Autocompletion for \code{$} access on a \code{\link{Seurat}} object #' #' @inheritParams utils::.DollarNames #' @param x A \code{\link{Seurat}} object #' #' @return The meta data matches for \code{pattern} #' #' @importFrom utils .DollarNames #' #' @keywords internal #' #' @method .DollarNames Seurat #' @export #' #' @concept seurat #' #' @inherit .DollarNames.Assay5 seealso #' ".DollarNames.Seurat" <- function(x, pattern = '') { meta.data <- as.list(x = colnames(x = x[[]])) names(x = meta.data) <- unlist(x = meta.data) return(.DollarNames(x = meta.data, pattern = pattern)) } #' Cell-Level Meta Data #' #' Get and set cell-level meta data #' #' @inheritParams .DollarNames.Seurat #' @param i Name of cell-level meta data #' @param j Ignored #' @template param-dots-ignored #' #' @return {$}: Metadata column \code{i} for object \code{x}; #' \strong{note}: unlike \code{[[}, \code{$} drops the shape of the metadata #' to return a vector instead of a data frame #' #' @method $ Seurat #' @export #' #' @family seurat #' #' @examples #' # Get metadata using `$' #' head(pbmc_small$groups) #' "$.Seurat" <- function(x, i) { return(x[[i, drop = TRUE]]) } #' @param value A vector to add as cell-level meta data #' #' @return \code{$<-}: \code{x} with metadata \code{value} saved as \code{i} #' #' @rdname cash-.Seurat #' #' @method $<- Seurat #' @export #' #' @examples #' # Add metadata using the `$' operator #' set.seed(42) #' pbmc_small$value <- sample(1:3, size = ncol(pbmc_small), replace = TRUE) #' head(pbmc_small[["value"]]) #' "$<-.Seurat" <- function(x, i, ..., value) { x[[i]] <- value return(x) } #' @return \code{[}: object \code{x} with features \code{i} and cells \code{j} #' #' @rdname subset.Seurat #' #' @method [ Seurat #' @export #' #' @order 2 #' #' @examples #' # `[` examples #' pbmc_small[VariableFeatures(object = pbmc_small), ] #' pbmc_small[, 1:10] #' "[.Seurat" <- function(x, i, j, ...) { x <- UpdateSlots(object = x) if (missing(x = i) && missing(x = j)) { return(x) } if (missing(x = i)) { i <- NULL } else if (missing(x = j)) { j <- colnames(x = x) } if (is.logical(x = i)) { if (length(i) != nrow(x = x)) { stop("Incorrect number of logical values provided to subset features") } i <- rownames(x = x)[i] } if (is.logical(x = j)) { if (length(j) != ncol(x = x)) { stop("Incorrect number of logical values provided to subset cells") } j <- colnames(x = x)[j] } if (is.numeric(x = i)) { i <- rownames(x = x)[i] } if (is.numeric(x = j)) { j <- colnames(x = x)[j] } return(subset.Seurat(x = x, features = i, cells = j, ...)) } #' Subobjects and Cell-Level Meta Data #' #' The \code{[[} operator pulls either subobjects #' (eg. \link[=Assay]{v3} or \link[=Assay5]{v5} assays, #' \link[=DimReduc]{dimensional reduction} information, #' or \link[=Graph]{nearest-neighbor graphs}) or cell-level #' meta data from a \code{\link{Seurat}} object #' #' @inheritParams $.Seurat #' @param drop See \code{\link[base]{drop}} #' @param na.rm Remove cells where meta data is all \code{NA} #' #' @return Varies based on the value of \code{i}: #' \itemize{ #' \item If \code{i} is missing, a data frame with cell-level meta data #' \item If \code{i} is a vector with cell-level meta data names, a data frame #' (or vector of \code{drop = TRUE}) with cell-level meta data requested #' \item If \code{i} is a one-length character with the #' \link[=names.Seurat]{name of a subobject}, the #' subobject specified by \code{i} #' } #' #' @method [[ Seurat #' @export #' #' @family seurat #' #' @seealso See \link[=$.Seurat]{here} for adding meta data with \code{[[<-}, #' \link[=[[<-,Seurat]{here} for adding subobjects with \code{[[<-}, and #' \link[=[[<-,Seurat,NULL]{here} for removing subobjects and cell-level meta #' data with \code{[[<-} #' #' @examples #' # Get the cell-level metadata data frame #' head(pbmc_small[[]]) #' #' # Pull specific metadata information #' head(pbmc_small[[c("letter.idents", "groups")]]) #' head(pbmc_small[["groups", drop = TRUE]]) #' #' # Get a sub-object (eg. an `Assay` or `DimReduc`) #' pbmc_small[["RNA"]] #' pbmc_small[["pca"]] #' "[[.Seurat" <- function(x, i = missing_arg(), ..., drop = FALSE, na.rm = FALSE) { md <- slot(object = x, name = 'meta.data') if (is_missing(x = i)) { return(md) } else if (is.null(x = i)) { return(NULL) } else if (!length(x = i)) { return(data.frame(row.names = row.names(x = md))) } # Correct invalid `i` meta.cols <- names(x = md) if (is_bare_integerish(x = i)) { if (all(i > length(x = meta.cols))) { abort(message = paste( "Invalid integer indexing:", "all integers greater than the number of meta columns" )) } i <- meta.cols[as.integer(x = i[i <= length(x = meta.cols)])] } if (!is.character(x = i)) { abort(message = "'i' must be a character vector") } # Determine if we're pulling cell-level meta data # or a sub-object slot.use <- if (length(x = i) == 1L) { .FindObject(object = x, name = i) } else { NULL } # Pull cell-level meta data if (is.null(x = slot.use)) { i <- tryCatch( expr = arg_match(arg = i, values = meta.cols, multiple = TRUE), error = function(e) { #error message that indicates which colnames not found abort( message = paste( paste(sQuote(x = setdiff(x = i, y = meta.cols)), collapse = ', '), "not found in this Seurat object\n", e$body ), call = rlang::caller_env(n = 4L) ) } ) # Pull the cell-level meta data data.return <- md[, i, drop = FALSE, ...] # If requested, remove NAs if (isTRUE(x = na.rm)) { idx.na <- apply(X = is.na(x = data.return), MARGIN = 1L, FUN = all) data.return <- data.return[!idx.na, , drop = FALSE] } else { idx.na <- rep_len(x = FALSE, length.out = ncol(x = x)) } # If requested, coerce to a vector if (isTRUE(x = drop)) { data.return <- unlist(x = data.return, use.names = FALSE) names(x = data.return) <- rep.int( x = colnames(x = x)[!idx.na], times = length(x = i) ) } return(data.return) } # Pull a sub-object return(slot(object = x, name = slot.use)[[i]]) } #' @inherit dim.Assay5 return title description details #' #' @inheritParams .DollarNames.Seurat #' #' @method dim Seurat #' @export #' #' @family seurat #' #' @examples #' # Get the number of features in an object #' nrow(pbmc_small) #' #' # Get the number of cells in an object #' ncol(pbmc_small) #' dim.Seurat <- function(x) { return(c( nrow(x = x[[DefaultAssay(object = x)]]) %||% 0L, length(x = colnames(x = x)) %||% 0L )) } #' Feature and Cell Names #' #' Get and set feature and cell inames in \code{\link{Seurat}} objects #' #' @inheritParams .DollarNames.Seurat #' @inheritParams dimnames.Assay5 #' #' @return \code{dimnames}: A two-length list with the following values: #' \itemize{ #' \item A character vector with all features in the #' \link[=DefaultAssay]{default assay} #' \item A character vector with all cells in \code{x} #' } #' #' @method dimnames Seurat #' @export #' #' @family seurat #' @family dimnames #' #' @examples #' # Get the feature names of an object #' head(rownames(pbmc_small)) #' #' # Get the cell names of an object #' head(colnames(pbmc_small)) #' dimnames.Seurat <- function(x) { return(list( rownames(x = x[[DefaultAssay(object = x)]]), row.names(x = slot(object = x, name = 'meta.data')) )) } #' @return \code{dimnames<-}: \code{x} with the feature and/or cell #' names updated to \code{value} #' #' @rdname dimnames.Seurat #' #' @method dimnames<- Seurat #' @export #' #' @examples #' colnames(pbmc_small)[1] <- "newcell" #' head(colnames(pbmc_small)) #' "dimnames<-.Seurat" <- function(x, value) { op <- options(Seurat.object.validate = FALSE) on.exit(expr = options(op), add = TRUE) # Check the provided dimnames msg <- "Invalid 'dimnames' given for a Seurat object" if (!is_bare_list(x = value, n = 2L)) { abort(message = msg) } else if (!all(sapply(X = value, FUN = length) == dim(x = x))) { abort(message = msg) } value <- lapply(X = value, FUN = as.character) onames <- dimnames(x = x) # Rename cells at the Seurat level names(x = slot(object = x, name = 'active.ident')) <- row.names(x = slot(object = x, name = 'meta.data')) <- value[[2L]] # Rename features/cells at the Assay level v3warn <- FALSE for (assay in Assays(object = x)) { anames <- dimnames(x = x[[assay]]) if (inherits(x = x[[assay]], what = 'StdAssay')) { afeatures <- MatchCells( new = onames[[1L]], orig = anames[[1L]], ordered = TRUE ) if (length(x = afeatures)) { idx <- MatchCells(new = anames[[1L]], orig = onames[[1L]]) anames[[1L]][idx] <- value[[1L]][afeatures] } } else if (isFALSE(x = v3warn) && any(onames[[1L]] != value[[1L]])) { warning( "Renaming features in v3/v4 assays is not supported", call. = FALSE, immediate. = TRUE ) v3warn <- TRUE } acells <- MatchCells(new = onames[[2L]], orig = anames[[2L]]) anames[[2L]] <- value[[2L]][acells] suppressWarnings(expr = dimnames(x = x[[assay]]) <- anames) } # Rename features/cells at the DimReduc level for (reduc in Reductions(object = x)) { rnames <- Cells(x = x[[reduc]]) rcells <- MatchCells(new = onames[[2L]], orig = rnames) suppressWarnings( expr = x[[reduc]] <- RenameCells( object = x[[reduc]], old.names = rnames, new.names = value[[2L]][rcells] ) ) if (!is.null(x = Features(x = x[[reduc]]))) { rfnames <- Features(x = x[[reduc]]) rfeatures <- MatchCells( new = onames[[1L]], orig = rfnames, ordered = TRUE ) if (length(x = rfeatures)) { suppressWarnings( expr = x[[reduc]] <- .RenameFeatures( object = x[[reduc]], old.names = rfnames, new.names = value[[1L]][rfeatures] ) ) } } } # TODO: Rename features/cells at the image level for (img in Images(object = x)) { inames <- Cells(x = x[[img]]) icells <- MatchCells(new = onames[[2L]], orig = inames) suppressWarnings( # TODO: replace with `x[[img]] <-` expr = slot(object = x, name = 'images')[[img]] <- RenameCells( object = x[[img]], old.names = inames, new.names = value[[2L]][icells] ) ) # TODO: rename features } # Rename cells at the Graph level for (graph in Graphs(object = x)) { gnames <- dimnames(x = x[[graph]]) for (i in seq_along(along.with = gnames)) { gcells <- MatchCells(new = onames[[2L]], orig = gnames[[i]]) gnames[[i]] <- value[[2L]][gcells] } suppressWarnings(expr = dimnames(x = x[[graph]]) <- gnames) } # Rename cells at the Neighbor level for (nn in Neighbors(object = x)) { nnames <- Cells(x = x[[nn]]) ncells <- MatchCells(new = onames[[2L]], orig = nnames) suppressWarnings( # TODO: replace with `x[[nn]] <-` expr = slot(object = x, name = 'neighbors')[[nn]] <- RenameCells( object = x[[nn]], old.names = nnames, new.names = value[[2L]][ncells] ) ) } # Validate and return options(op) validObject(object = x) return(x) } #' @rdname Idents #' @export #' @method droplevels Seurat #' droplevels.Seurat <- function(x, ...) { x <- UpdateSlots(object = x) slot(object = x, name = 'active.ident') <- droplevels(x = Idents(object = x), ...) return(x) } #' @param n Number of meta data rows to show #' #' @return \code{head}: The first \code{n} rows of cell-level metadata #' #' @rdname sub-sub-.Seurat #' #' @method head Seurat #' @export #' #' @examples #' # Get the first 10 rows of cell-level metadata #' head(pbmc_small) #' head.Seurat <- .head #' @rdname Idents #' @export #' @method levels Seurat #' #' @examples #' # Get the levels of identity classes of a Seurat object #' levels(x = pbmc_small) #' levels.Seurat <- function(x) { x <- UpdateSlots(object = x) return(levels(x = Idents(object = x))) } #' @rdname Idents #' @export #' @method levels<- Seurat #' #' @examples #' # Reorder identity classes #' levels(x = pbmc_small) #' levels(x = pbmc_small) <- c('C', 'A', 'B') #' levels(x = pbmc_small) #' "levels<-.Seurat" <- function(x, value) { x <- UpdateSlots(object = x) idents <- Idents(object = x) if (!all(levels(x = idents) %in% value)) { stop("NA's generated by missing levels", call. = FALSE) } idents <- factor(x = idents, levels = value) Idents(object = x) <- idents return(x) } #' Merge Seurat Objects #' #' @inheritParams CreateSeuratObject #' @inheritParams merge.Assay5 #' @param x A \code{\link{Seurat}} object #' @param y A single \code{Seurat} object or a list of \code{Seurat} objects #' @param add.cell.ids A character vector of \code{length(x = c(x, y))}; #' appends the corresponding values to the start of each objects' cell names #' @param merge.data Merge the data slots instead of just merging the counts #' (which requires renormalization); this is recommended if the same #' normalization approach was applied to all objects #' @param merge.dr Choose how to handle merging dimensional reductions: #' \itemize{ #' \item \dQuote{\code{TRUE}}: merge dimensional reductions with the same name #' across objects; dimensional reductions with different names are added as-is #' \item \dQuote{\code{NA}}: keep dimensional reductions from separate objects #' separate; will append the project name for duplicate reduction names #' \item \dQuote{\code{FALSE}}: do not add dimensional reductions #' } #' #' @return \code{merge}: Merged object #' #' @section Merge Details: #' When merging Seurat objects, the merge procedure will merge the Assay level #' counts and potentially the data slots (depending on the merge.data parameter). #' It will also merge the cell-level meta data that was stored with each object #' and preserve the cell identities that were active in the objects pre-merge. #' The merge will optionally merge reductions depending on the values passed to #' \code{merge.dr} if they have the same name across objects. Here the #' embeddings slots will be merged and if there are differing numbers of #' dimensions across objects, only the first N shared dimensions will be merged. #' The feature loadings slots will be filled by the values present in the first #' object.The merge will not preserve graphs, logged commands, or feature-level #' metadata that were present in the original objects. If add.cell.ids isn't #' specified and any cell names are duplicated, cell names will be appended #' with _X, where X is the numeric index of the object in c(x, y). #' #' @method merge Seurat #' @export #' #' @family seurat #' #' @aliases merge MergeSeurat AddSamples #' #' @examples #' # `merge' examples #' # merge two objects #' merge(pbmc_small, y = pbmc_small) #' # to merge more than two objects, pass one to x and a list of objects to y #' merge(pbmc_small, y = c(pbmc_small, pbmc_small)) #' merge.Seurat <- function( x = NULL, y = NULL, add.cell.ids = NULL, collapse = FALSE, merge.data = TRUE, merge.dr = FALSE, project = getOption(x = 'Seurat.object.project', default = 'SeuratProject'), ... ) { CheckDots(...) objects <- c(x, y) projects <- vapply( X = objects, FUN = Project, FUN.VALUE = character(length = 1L) ) if (anyDuplicated(x = projects)) { projects <- as.character(x = seq_along(along.with = objects)) } # Check cell names if (is_na(x = add.cell.ids)) { add.cell.ids <- as.character(x = seq_along(along.with = objects)) } else if (isTRUE(x = add.cell.ids)) { add.cell.ids <- projects } if (!is.null(x = add.cell.ids)) { if (length(x = add.cell.ids) != length(x = objects)) { abort( message = "Please provide a cell identifier for each object provided to merge" ) } # for (i in seq_along(along.with = add.cell.ids)) { # colnames(x = objects[[i]]) <- paste( # colnames(x = objects[[i]]), # add.cell.ids[[i]], # sep = '_' # ) # } for (i in 1:length(x = objects)) { objects[[i]] <- RenameCells(object = objects[[i]], add.cell.id = add.cell.ids[i]) } } objects <- CheckDuplicateCellNames(object.list = objects) # Merge assays assays <- Reduce(f = union, x = lapply(X = objects, FUN = Assays)) assay.classes <- sapply( X = assays, FUN = function(a) { cls <- vector(mode = 'character', length = length(x = objects)) for (i in seq_along(along.with = cls)) { cls[i] <- if (a %in% Assays(object = objects[[i]])) { class(x = objects[[i]][[a]])[1L] } else { NA_character_ } } return(unique(x = cls[!is.na(x = cls)])) }, simplify = FALSE, USE.NAMES = TRUE ) # TODO: Handle merging v3 and v5 assays # if (any(sapply(X = assay.classes, FUN = length) != 1L)) { # stop("Cannot merge assays of different classes") # } assays.all <- vector(mode = 'list', length = length(x = assays)) names(x = assays.all) <- assays for (assay in assays) { assay.objs <- which(x = vapply( X = lapply(X = objects, FUN = names), FUN = '%in%', FUN.VALUE = logical(length = 1L), x = assay )) if (length(x = assay.objs) == 1L) { assays.all[[assay]] <- objects[[assay.objs]][[assay]] next } idx.x <- assay.objs[[1L]] idx.y <- setdiff(x = assay.objs, y = idx.x) assays.all[[assay]] <- merge( x = objects[[idx.x]][[assay]], y = lapply(X = objects[idx.y], FUN = '[[', assay), labels = projects, add.cell.ids = NULL, collapse = collapse, merge.data = merge.data ) } names(objects) <- NULL all.cells <- Reduce(f = union, x = lapply(X = objects, FUN = colnames)) idents.all <- unlist(x = lapply(X = objects, FUN = Idents)) idents.all <- idents.all[all.cells] md.all <- EmptyDF(n = length(x = all.cells)) row.names(x = md.all) <- all.cells obj.combined <- new( Class = 'Seurat', assays = assays.all, reductions = list(), images = list(), meta.data = md.all, active.assay = DefaultAssay(object = x), active.ident = idents.all, project.name = project ) # Merge cell-level meta data, images for (i in seq_along(along.with = objects)) { df <- data.frame( lapply(objects[[i]][[]], FUN = function(x) { if (is.factor(x)) as.character(x) else x }), stringsAsFactors=FALSE ) rownames(df) <- rownames(objects[[i]][[]]) obj.combined[[]] <- df for (img in Images(object = objects[[i]])) { dest <- ifelse( test = img %in% Images(object = obj.combined), yes = paste(img, projects[i], sep = '.'), no = img ) obj.combined[[dest]] <- objects[[i]][[img]] } } # Merge dimensional reductions reducs.combined <- list() if (is.character(x = merge.dr)) { warn(message = "'merge.Seurat' no longer supports filtering dimensional reductions; merging all dimensional reductions") merge.dr <- TRUE } if (isTRUE(x = merge.dr)) { for (i in seq_along(along.with = objects)) { for (reduc in Reductions(object = objects[[i]])) { reducs.combined[[reduc]] <- if (reduc %in% names(x = reducs.combined)) { inform(message = paste("Merging reduction", sQuote(x = reduc))) merge(x = reducs.combined[[reduc]], y = objects[[i]][[reduc]]) } else { objects[[i]][[reduc]] } } } } else if (is_na(x = merge.dr)) { reducs.all <- unlist( x = lapply(X = objects, FUN = Reductions), use.names = FALSE ) reducs.dup <- unique(x = reducs.all[duplicated(x = reducs.all)]) for (i in seq_along(along.with = objects)) { for (reduc in Reductions(object = objects[[i]])) { rname <- ifelse( test = reduc %in% reducs.dup, yes = paste(reduc, projects[i], sep = '.'), no = reduc ) reducs.combined[[rname]] <- objects[[i]][[reduc]] if (rname != reduc) { inform(message = paste( "Changing", reduc, "in object", projects[i], "to", rname )) new.key <- Key(object = rname, quiet = TRUE) inform(message = paste("Updating key to", new.key)) Key(object = reducs.combined[[rname]]) <- new.key } } } } for (reduc in names(x = reducs.combined)) { obj.combined[[reduc]] <- reducs.combined[[reduc]] } # Validate and return validObject(object = obj.combined) return(obj.combined) # Merge DimReducs combined.reductions <- list() if (!is.null(x = merge.dr)) { for (dr in merge.dr) { drs.to.merge <- list() for (i in 1:length(x = objects)) { if (!dr %in% Reductions(object = objects[[i]])) { warning("The DimReduc ", dr, " is not present in all objects being ", "merged. Skipping and continuing.", call. = FALSE, immediate. = TRUE) break } drs.to.merge[[i]] <- objects[[i]][[dr]] } if (length(x = drs.to.merge) == length(x = objects)) { combined.reductions[[dr]] <- merge( x = drs.to.merge[[1]], y = drs.to.merge[2:length(x = drs.to.merge)] ) } } } } #' Subobject Names #' #' Get the names of subobjects within a \code{\link{Seurat}} object #' #' @inheritParams .DollarNames.Seurat #' #' @return The names of all of the following subobjects within \code{x}: #' \itemize{ #' \item \link[=Assay]{v3} and \link[=Assay5]{v5} assays #' \item \link[=DimReduc]{dimensional reductions} #' \item \link[=SpatialImage]{images} and \link[=FOV]{FOVs} #' \item \link[=Graph]{nearest-neighbor graphs} #' } #' #' @method names Seurat #' @export #' #' @family seurat #' #' @examples #' names(pbmc_small) #' names.Seurat <- function(x) { return(.FilterObjects( object = x, classes.keep = c('Assay', 'StdAssay', 'DimReduc', 'Graph', 'SpatialImage') )) } #' @inherit split.Assay5 params return title description details sections #' #' @keywords internal #' @method split Seurat #' @export #' #' @family Seurat #' split.Seurat <- function( x, f, drop = FALSE, assay = NULL, layers = NA, ... ){ assay <- assay %||% DefaultAssay(x) x[[assay]] <- split( x = x[[assay]], f = f, drop = drop, layers = layers, ret = 'assay', ... ) return(x) } #' Subset \code{Seurat} Objects #' #' @inheritParams .DollarNames.Seurat #' @inheritParams CellsByIdentities #' @param subset Logical expression indicating features/variables to keep #' @param cells,j A vector of cell names or indices to keep #' @param features,i A vector of feature names or indices to keep #' @param idents A vector of identity classes to keep #' @param ... Arguments passed to \code{\link{WhichCells}} #' #' @return \code{subset}: A subsetted \code{Seurat} object #' #' @importFrom rlang enquo #' #' @export #' @method subset Seurat #' #' @family seurat # #' @seealso \code{\link{WhichCells}} #' #' @aliases subset #' #' @order 1 #' #' @examples #' # `subset` examples #' subset(pbmc_small, subset = MS4A1 > 4) #' subset(pbmc_small, subset = `DLGAP1-AS1` > 2) #' subset(pbmc_small, idents = '0', invert = TRUE) #' subset(pbmc_small, subset = MS4A1 > 3, slot = 'counts') #' subset(pbmc_small, features = VariableFeatures(object = pbmc_small)) #' subset.Seurat <- function( x, subset, cells = NULL, features = NULL, idents = NULL, return.null = FALSE, ... ) { # var.features <- VariableFeatures(object = x) if (!missing(x = subset)) { subset <- enquo(arg = subset) } cells <- WhichCells( object = x, cells = cells, idents = idents, expression = subset, return.null = TRUE, ... ) if (length(x = cells) == 0) { if (isTRUE(x = return.null)) { return(NULL) } abort(message = "No cells found") } if (all(cells %in% Cells(x = x)) && length(x = cells) == length(x = colnames(x = x)) && is.null(x = features) ) { return(x) } op <- options(Seurat.object.validate = FALSE, Seurat.object.assay.calcn = FALSE) on.exit(expr = options(op), add = TRUE) # Remove metadata for cells not present orig.cells <- colnames(x = x) cells <- intersect(x = orig.cells, y = cells) slot(object = x, name = 'meta.data') <- x[[]][cells, , drop = FALSE] if (!all(orig.cells %in% cells)) { # Remove neighbors slot(object = x, name = 'neighbors') <- list() # Filter Graphs for (g in names(slot(object = x, name = 'graphs'))) { cells.g <- intersect(colnames(x[[g]]), cells) suppressWarnings( expr = x[[g]] <- as.Graph(x = x[[g]][cells.g, cells.g, drop = FALSE]) ) } } Idents(object = x, drop = TRUE) <- Idents(object = x)[cells] # Filter Assay objects for (assay in Assays(object = x)) { if (length(x = intersect(colnames(x = x[[assay]]), cells)) == 0) { message(assay, " assay doesn't leave any cells, so it is removed") if (DefaultAssay(x) == assay) { stop('No cells left in the default assay, please change the default assay') } slot(object = x, name = 'assays')[[assay]] <- NULL } else { assay.features <- features %||% rownames(x = x[[assay]]) suppressWarnings( expr = slot(object = x, name = 'assays')[[assay]] <- tryCatch( # because subset is also an argument, we need to explictly use the base::subset function expr = suppressWarnings( expr = base::subset( x = x[[assay]], cells = cells, features = assay.features ), classes = 'validationWarning' ), error = function(e) { if (e$message == "Cannot find features provided") { return(NULL) } else { stop(e) } } ) ) } } slot(object = x, name = 'assays') <- Filter( f = Negate(f = is.null), x = slot(object = x, name = 'assays') ) if (length(x = .FilterObjects(object = x, classes.keep = c('Assay', 'StdAssay'))) == 0 || is.null(x = x[[DefaultAssay(object = x)]])) { abort(message = "Under current subsetting parameters, the default assay will be removed. Please adjust subsetting parameters or change default assay") } # Filter DimReduc objects for (dimreduc in .FilterObjects(object = x, classes.keep = 'DimReduc')) { suppressWarnings( x[[dimreduc]] <- tryCatch( expr = subset.DimReduc(x = x[[dimreduc]], cells = cells, features = features), error = function(e) { if (e$message %in% c("Cannot find cell provided", "Cannot find features provided")) { return(NULL) } else { stop(e) } } ) ) } # Recalculate nCount and nFeature if (!is.null(features)) { for (assay in .FilterObjects(object = x, classes.keep = 'Assay')) { n.calc <- CalcN(object = x[[assay]]) if (!is.null(x = n.calc)) { names(x = n.calc) <- paste(names(x = n.calc), assay, sep = '_') suppressWarnings( expr = x[[names(x = n.calc)]] <- n.calc, classes = 'validationWarning' ) } } } # # set variable features # if (!is.null(var.features)) { # suppressWarnings( # expr = VariableFeatures(object = x) <- var.features, # classes = 'validationWarning' # ) # } # subset images for (image in Images(object = x)) { x[[image]] <- base::subset(x = x[[image]], cells = cells) } return(x) } #' @return \code{tail}: The last \code{n} rows of cell-level metadata #' #' @rdname sub-sub-.Seurat #' #' @method tail Seurat #' @export #' #' @examples #' # Get the last 10 rows of cell-level metadata #' tail(pbmc_small) #' tail.Seurat <- .tail #' @method upgrade seurat #' @export #' upgrade.seurat <- function(object, ...) { # Run update message("Updating from v2.X to v3.X") seurat.version <- packageVersion(pkg = "SeuratObject") new.assay <- UpdateAssay(old.assay = object, assay = "RNA") assay.list <- list(RNA = new.assay) for (i in names(x = object@assay)) { assay.list[[i]] <- UpdateAssay(old.assay = object@assay[[i]], assay = i) } new.dr <- UpdateDimReduction(old.dr = object@dr, assay = "RNA") object <- new( Class = "Seurat", version = seurat.version, assays = assay.list, active.assay = "RNA", project.name = object@project.name, misc = object@misc %||% list(), active.ident = object@ident, reductions = new.dr, meta.data = object@meta.data, tools = list() ) # Run CalcN for (assay in Assays(object = object)) { n.calc <- CalcN(object = object[[assay]]) if (!is.null(x = n.calc)) { names(x = n.calc) <- paste(names(x = n.calc), assay, sep = '_') object[[names(x = n.calc)]] <- n.calc } for (i in c('nGene', 'nUMI')) { if (i %in% colnames(x = object[[]])) { object[[i]] <- NULL } } } } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # S4 methods #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' Original double-bracket assign #' #' This function has been replaced with value-specific double-bracket #' assign methods and should generally not be called #' #' @param x A \code{\link{Seurat}} object #' @param i The name to store a subobject or various cell-level meta data as #' @param value New subobject or cell-level meta data #' #' @return \code{x} with \code{value} stored as \code{i} #' #' @name old-assign #' @rdname old-assign #' #' @keywords internal #' #' @seealso See \link[=$.Seurat]{here} for adding metadata with \code{[[<-}, and #' \link[=[[<-,Seurat,NULL]{here} for removing subobjects and cell-level meta #' data with \code{[[<-} #' NULL #' @rdname old-assign #' setMethod( # because R doesn't allow S3-style [[<- for S4 classes f = '[[<-', signature = c('x' = 'Seurat', i = 'character', value = 'ANY'), definition = function(x, i, ..., value) { x <- UpdateSlots(object = x) # Require names, no index setting if (!is.character(x = i)) { stop("'i' must be a character", call. = FALSE) } # Allow removing of other object if (is.null(x = value)) { slot.use <- if (i %in% colnames(x = x[[]])) { 'meta.data' } else { FindObject(object = x, name = i) } if (is.null(x = slot.use)) { stop("Cannot find object ", i, call. = FALSE) } if (i == DefaultAssay(object = x)) { stop("Cannot delete the default assay", call. = FALSE) } } # remove disallowed characters from object name newi <- if (is.null(x = value)) { i } else { make.names(names = i) } if (any(i != newi)) { warning( "Invalid name supplied, making object name syntactically valid. New object name is ", newi, "; see ?make.names for more details on syntax validity", call. = FALSE, immediate. = TRUE ) i <- newi } # Figure out where to store data slot.use <- if (inherits(x = value, what = 'Assay')) { # Ensure we have the same number of cells if (ncol(x = value) != ncol(x = x)) { stop( "Cannot add a different number of cells than already present", call. = FALSE ) } # Ensure cell order stays the same if (all(Cells(x = value) %in% Cells(x = x)) && !all(Cells(x = value) == Cells(x = x))) { for (slot in c('counts', 'data', 'scale.data')) { assay.data <- GetAssayData(object = value, layer = slot) if (!IsMatrixEmpty(x = assay.data)) { assay.data <- assay.data[, Cells(x = x), drop = FALSE] } # Use slot because SetAssayData is being weird slot(object = value, name = slot) <- assay.data } } 'assays' } else if (inherits(x = value, what = 'SpatialImage')) { # Ensure that all cells for this image are present if (!all(Cells(x = value) %in% Cells(x = x))) { stop("All cells in the image must be present in assay.", call. = FALSE) } # Ensure Assay that SpatialImage is associated with is present in Seurat object if (!DefaultAssay(object = value) %in% Assays(object = x)) { warning( "Adding image data that isn't associated with any assay present", call. = FALSE, immediate. = TRUE ) } 'images' } else if (inherits(x = value, what = 'Graph')) { # Ensure Assay that Graph is associated with is present in the Seurat object if (is.null(x = DefaultAssay(object = value))) { warning( "Adding a Graph without an assay associated with it", call. = FALSE, immediate. = TRUE ) } else if (!any(DefaultAssay(object = value) %in% Assays(object = x))) { stop("Cannot find assay '", DefaultAssay(object = value), "' in this Seurat object", call. = FALSE) } # Ensure Graph object is in order if (all(Cells(x = value) %in% Cells(x = x)) && !all(Cells(x = value) == Cells(x = x))) { value <- value[Cells(x = x), Cells(x = x)] } 'graphs' } else if (inherits(x = value, what = 'DimReduc')) { # All DimReducs must be associated with an Assay if (is.null(x = DefaultAssay(object = value))) { stop("Cannot add a DimReduc without an assay associated with it", call. = FALSE) } # Ensure Assay that DimReduc is associated with is present in the Seurat object if (!IsGlobal(object = value) && !any(DefaultAssay(object = value) %in% Assays(object = x))) { stop("Cannot find assay '", DefaultAssay(object = value), "' in this Seurat object", call. = FALSE) } # Ensure DimReduc object is in order if (all(Cells(x = value) %in% Cells(x = x)) && !all(Cells(x = value) == Cells(x = x))) { slot(object = value, name = 'cell.embeddings') <- value[[Cells(x = x), ]] } 'reductions' } else if (inherits(x = value, what = "Neighbor")) { # Ensure all cells are present in the Seurat object if (length(x = Cells(x = value)) > length(x = Cells(x = x))) { stop( "Cannot have more cells in the Neighbor object than are present in the Seurat object.", call. = FALSE ) } if (!all(Cells(x = value) %in% Cells(x = x))) { stop( "Cannot add cells in the Neighbor object that aren't present in the Seurat object.", call. = FALSE ) } 'neighbors' } else if (inherits(x = value, what = 'SeuratCommand')) { # Ensure Assay that SeuratCommand is associated with is present in the Seurat object if (is.null(x = DefaultAssay(object = value))) { warning( "Adding a command log without an assay associated with it", call. = FALSE, immediate. = TRUE ) } else if (!any(DefaultAssay(object = value) %in% Assays(object = x))) { stop("Cannot find assay '", DefaultAssay(object = value), "' in this Seurat object", call. = FALSE) } 'commands' } else if (is.null(x = value)) { slot.use } else { 'meta.data' } if (slot.use == 'meta.data') { # Add data to object metadata meta.data <- x[[]] cell.names <- rownames(x = meta.data) # If we have metadata with names, ensure they match our order if (is.data.frame(x = value) && !is.null(x = rownames(x = value))) { meta.order <- match(x = rownames(x = meta.data), table = rownames(x = value)) value <- value[meta.order, , drop = FALSE] } if (length(x = i) > 1) { # Add multiple pieces of metadata value <- rep_len(x = value, length.out = length(x = i)) for (index in 1:length(x = i)) { meta.data[i[index]] <- value[index] } } else { # Add a single column to metadata if (length(x = intersect(x = names(x = value), y = cell.names)) > 0) { meta.data[, i] <- value[cell.names] } else if (length(x = value) %in% c(nrow(x = meta.data), 1) || is.null(x = value)) { meta.data[, i] <- value } else { stop("Cannot add more or fewer cell meta.data information without values being named with cell names", call. = FALSE) } } # Check to ensure that we aren't adding duplicate names if (any(colnames(x = meta.data) %in% FilterObjects(object = x))) { bad.cols <- colnames(x = meta.data)[which(colnames(x = meta.data) %in% FilterObjects(object = x))] stop( paste0( "Cannot add a metadata column with the same name as an Assay or DimReduc - ", paste(bad.cols, collapse = ", ")), call. = FALSE ) } # Store the revised metadata slot(object = x, name = 'meta.data') <- meta.data } else { # Add other object to Seurat object # Ensure cells match in value and order if (!inherits(x = value, what = c('SeuratCommand', 'NULL', 'SpatialImage', 'Neighbor')) && !all(Cells(x = value) == colnames(x = x))) { stop("All cells in the object being added must match the cells in this object", call. = FALSE) } # Ensure we're not duplicating object names duplicate <- !is.null(x = FindObject(object = x, name = i)) && !inherits(x = value, what = c(class(x = x[[i]]), 'NULL')) && !inherits(x = x[[i]], what = class(x = value)) if (isTRUE(x = duplicate)) { stop( "This object already contains ", i, " as a", ifelse( test = tolower(x = substring(text = class(x = x[[i]]), first = 1, last = 1)) %in% c('a', 'e', 'i', 'o', 'u'), yes = 'n ', no = ' ' ), class(x = x[[i]]), ", so ", i, " cannot be used for a ", class(x = value), call. = FALSE ) } # Check keyed objects if (inherits(x = value, what = c('Assay', 'DimReduc', 'SpatialImage'))) { if (length(x = Key(object = value)) == 0 || nchar(x = Key(object = value)) == 0) { Key(object = value) <- paste0(tolower(x = i), '_') } Key(object = value) <- UpdateKey(key = Key(object = value)) # Check for duplicate keys object.keys <- Key(object = x) vkey <- Key(object = value) if (vkey %in% object.keys && !isTRUE(x = object.keys[i] == vkey)) { new.key <- if (is.na(x = object.keys[i])) { # Attempt to create a duplicate key based off the name of the object being added new.keys <- paste0( paste0(tolower(x = i), c('', RandomName(length = 2L))), '_' ) # Select new key to use key.use <- min(which(x = !new.keys %in% object.keys)) new.key <- if (is.infinite(x = key.use)) { RandomName(length = 17L) } else { new.keys[key.use] } warning( "Cannot add objects with duplicate keys (offending key: ", Key(object = value), "), setting key to '", new.key, "'", call. = FALSE ) new.key } else { # Use existing key warning( "Cannot add objects with duplicate keys (offending key: ", Key(object = value), ") setting key to original value '", object.keys[i], "'", call. = FALSE ) object.keys[i] } # Set new key Key(object = value) <- new.key } } # For Assays, run CalcN if (inherits(x = value, what = 'Assay')) { if ((!i %in% Assays(object = x)) | (i %in% Assays(object = x) && !identical( x = GetAssayData(object = x, assay = i, layer = "counts"), y = GetAssayData(object = value, layer = "counts")) )) { n.calc <- CalcN(object = value) if (!is.null(x = n.calc)) { names(x = n.calc) <- paste(names(x = n.calc), i, sep = '_') x[[names(x = n.calc)]] <- n.calc } } } # When removing an Assay, clear out associated DimReducs, Graphs, and SeuratCommands if (is.null(x = value) && inherits(x = x[[i]], what = 'Assay')) { objs.assay <- FilterObjects( object = x, classes.keep = c('DimReduc', 'SeuratCommand', 'Graph') ) objs.assay <- Filter( f = function(o) { return(all(DefaultAssay(object = x[[o]]) == i) && !IsGlobal(object = x[[o]])) }, x = objs.assay ) for (o in objs.assay) { x[[o]] <- NULL } } # If adding a command, ensure it gets put at the end of the command list if (inherits(x = value, what = 'SeuratCommand')) { slot(object = x, name = slot.use)[[i]] <- NULL slot(object = x, name = slot.use) <- Filter( f = Negate(f = is.null), x = slot(object = x, name = slot.use) ) } slot(object = x, name = slot.use)[[i]] <- value slot(object = x, name = slot.use) <- Filter( f = Negate(f = is.null), x = slot(object = x, name = slot.use) ) } CheckGC() return(x) } ) #' Add Subobjects #' #' Add subobjects containing expression, dimensional reduction, or other #' containerized data to a \code{\link{Seurat}} object. Subobjects can be #' accessed with \code{\link[=[[.Seurat]{[[}} and manipulated directly within #' the \code{Seurat} object or used independently #' #' @inheritParams .DollarNames.Seurat #' @inheritParams [[.Assay5 #' @param i Name to add subobject as #' @param value A valid subobject (eg. a \link[=Assay]{v3} or \link[=Assay5]{v5} #' assay, or a \link[=DimReduc]{dimensional reduction}) #' #' @return \code{x} with \code{value} added as \code{i} #' #' @name [[<-,Seurat #' @rdname sub-subset-Seurat #' #' @family seurat #' #' @seealso See \link[=[[.Seurat]{here} for pulling subobjects using \code{[[}, #' \link[=$.Seurat]{here} for adding metadata with \code{[[<-}, and #' \link[=[[<-,Seurat,NULL]{here} for removing subobjects and cell-level meta #' data with \code{[[<-} #' #' @aliases [[<-.Seurat \S4method{[[<-}{Seurat,character,missing,Assay} #' NULL #' @rdname sub-subset-Seurat #' setMethod( f = '[[<-', signature = c( x = 'Seurat', i = 'character', j = 'missing', value = 'Assay' ), definition = function(x, i, ..., value) { if (.GetSeuratCompat() < '5.0.0') { return(callNextMethod(x = x, i = i, value = value)) } validObject(object = value) i <- make.names(names = i) # Checks for if the assay or name already exists if (i %in% names(x = x)) { if (!inherits(x = x[[i]], what = c('Assay', 'StdAssay'))) { abort( message = paste( sQuote(i), "already exists as an object of class", class(x = x[[i]])[1L] ), class = 'duplicateError' ) } if (!identical(x = class(x = value), y = class(x = x[[i]]))) { warning( "Assay ", i, " changing from ", class(x = x[[i]]), " to ", class(x = value), call. = FALSE, immediate. = TRUE ) } if (!all(dim(x = value) == dim(x = x[[i]]))) { warn( message = paste0("Different cells and/or features from existing assay ", i), class = 'dimWarning' ) } } # Check for cells if (!all(colnames(x = value) %in% colnames(x = x))) { abort(message = "Cannot add new cells with [[<-") } cell.order <- MatchCells( new = colnames(x = value), orig = colnames(x = x), ordered = TRUE ) # TODO: enable reordering cells in assay if (is.unsorted(x = cell.order)) { if (inherits(x = value, what = 'Assay')) { for (s in c('counts', 'data', 'scale.data')) { if (!IsMatrixEmpty(x = slot(object = value, name = s))) { slot(object = value, name = s) <- slot(object = value, name = s)[, cell.order] } } } else { abort(message = "Cannot add assays with unordered cells") } validObject(object = value) } # Check keys Key(object = value) <- .CheckKey( key = Key(object = value), existing = Key(object = x), name = i ) # Run CalcN do.calcn <- Misc(object = value, slot = 'calcN') %||% FALSE suppressWarnings(Misc(object = value, slot = 'calcN') <- NULL) if (isTRUE(x = do.calcn)) { n.calc <- suppressWarnings( expr = .CalcN(object = value, layer = 'counts', simplify = TRUE), classes = 'missingLayerWarning' ) if (!is.null(x = n.calc)) { names(x = n.calc) <- paste(names(x = n.calc), i, sep = '_') x[[]] <- n.calc } } # Add the assay slot(object = x, name = 'assays')[[i]] <- value slot(object = x, name = 'assays') <- Filter( f = Negate(f = is.null), x = slot(object = x, name = 'assays') ) # Validate and return validObject(object = x) return(x) } ) #' @rdname sub-subset-Seurat #' setMethod( f = '[[<-', signature = c( x = 'Seurat', i = 'character', j = 'missing', value = 'Assay5' ), definition = function(x, i, ..., value) { return(callNextMethod(x = x, i = i, ..., value = value)) } ) #' @rdname cash-.Seurat #' setMethod( f = '[[<-', signature = c( x = 'Seurat', i = 'character', j = 'missing', value = 'data.frame' ), definition = function(x, i, ..., value) { # Because R is stupid sometimes if (!length(x = i) && !ncol(x = value)) { return(x) } # Check the names provided if (length(x = i) == ncol(x = value)) { # Add the names to the meta data if (is.null(x = names(x = value))) { names(x = value) <- i } if (ncol(x = value) == 1) { v <- value[,1] names(x = v) <- rownames(x = value) x[[i]] <- v return(x) } idx <- match(x = i, table = names(x = value)) # If there are any mismatches in `i` and `names(value)` # rename `value` to match `i` # if (all(is.na(x = idx))) { # warn(message = paste( # "None of the column names are found in meta data names;", # "replacing to provided meta data names" # )) # } if (any(is.na(x = idx))) { meta.missing <- setdiff( x = seq_len(length.out = ncol(x = value)), y = idx[!is.na(x = idx)] ) names(x = meta.missing) <- i[is.na(x = idx)] # for (j in seq_along(along.with = meta.missing)) { # warn(message = paste( # "Column", # sQuote(x = names(x = value)[meta.missing[j]]), # "not found in meta data names, changing to", # sQuote(x = names(x = meta.missing)[j]) # )) # } names(x = value)[meta.missing] <- names(x = meta.missing) } } else if (is.null(x = names(x = value))) { # Cannot add meta data without names abort(message = paste( "Cannot assign", length(x = i), ifelse(test = length(x = i) == 1L, yes = 'name', no = 'names'), "to", ncol(x = value), ifelse(test = ncol(x = value) == 1L, yes = 'bit', no = 'bits'), "of meta data" )) } else { # Find matching `i` in `names(value)` # Cannot rename as `length(i) != ncol(value)` i.orig <- i i <- intersect(x = i, y = names(x = value)) # If no matching, abort if (!length(x = i)) { abort( message = "None of the meta data requested was found in the data frame" ) } # Alert user to `i` not found in `names(value)` i.missing <- setdiff(x = i.orig, y = i) if (length(x = i.missing)) { warn(message = paste( "The following bits of meta data in the data frame will not be added:", paste(sQuote(x = i.missing), collapse = ', ') )) } } # Handle meta data for different cells names.intersect <- intersect(x = row.names(x = value), y = colnames(x = x)) if (length(x = names.intersect)) { value <- value[names.intersect, , drop = FALSE] if (!nrow(x = value)) { abort(message = "None of the cells provided are in this Seurat object") } } else if (nrow(x = value) == ncol(x = x)) { # When no cell names are provided in value, assume it's in cell order row.names(x = value) <- colnames(x = x) } else { # Throw an error when no cell names provided and cannot assume cell order abort( message = "Cannot add more or less meta data without cell names" ) } # Add the cell-level meta data using the `value = vector` method for (n in i) { v <- value[[n]] names(x = v) <- row.names(x = value) x[[n]] <- v } return(x) } ) #' @rdname cash-.Seurat #' setMethod( f = '[[<-', signature = c( x = 'Seurat', i = 'missing', j = 'missing', value = 'data.frame' ), definition = function(x, i, ..., value) { # Allow removing all meta data if (IsMatrixEmpty(x = value)) { x[[names(x = x[[]])]] <- NULL } else { # If no `i` provided, use the column names from value x[[names(x = value)]] <- value } return(x) } ) #' @rdname sub-subset-Seurat #' setMethod( f = '[[<-', signature = c( x = 'Seurat', i = 'character', j = 'missing', value = 'DimReduc' ), definition = function(x, i, ..., value) { validObject(object = value) i <- make.names(names = i) # Checks for if the DimReduc or name already exists if (i %in% .Subobjects(object = x)) { if (!inherits(x = x[[i]], what = 'DimReduc')) { abort( message = paste( sQuote(i), "already exists as an object of class", class(x = x[[i]])[1L] ), class = 'duplicateError' ) } if (!identical(x = class(x = value), y = class(x = x[[i]]))) { warning( "DimReduc ", i, " changing from ", class(x = x[[i]]), " to ", class(x = value), call. = FALSE, immediate. = TRUE ) } if (length(x = value) != length(x = x[[i]])) { warning( "Number of dimensions changing from ", length(x = x[[i]]), " to ", length(x = value), call. = FALSE, immediate. = TRUE ) } if (length(x = Cells(x = value)) != length(x = Cells(x = x[[i]]))) { warning( "Number of cells changing from ", length(x = Cells(x = x[[i]])), " to ", length(x = Cells(x = value)), call. = FALSE, immediate. = TRUE ) } } # Check default assay if (is.null(x = DefaultAssay(object = value))) { stop("Cannot add a DimReduc without an associated assay", call. = FALSE) } else if (!any(DefaultAssay(object = value) %in% Assays(object = x))) { warning( "Adding a dimensional reduction (", i, ") without the associated assay being present", call. = FALSE, immediate. = TRUE ) } # Check for cells if (!all(Cells(x = value) %in% colnames(x = x))) { stop("Cannot add new cells with [[<-", call. = FALSE) } cell.order <- MatchCells( new = Cells(x = value), orig = colnames(x = x), ordered = TRUE ) # TODO: enable reordering cells in DimReducs if (is.unsorted(x = cell.order)) { ordered.cells <- intersect(colnames(x = x), Cells(x = value)) slot(object = value, name = 'cell.embeddings') <- Embeddings(object = value)[ordered.cells,] } # Check keys Key(object = value) <- .CheckKey( key = Key(object = value), existing = Key(object = x), name = i ) # Check loadings and embeddings column name emb.names <- paste0(sapply( X = strsplit( x = colnames(Embeddings(object = value)), split = '_'), FUN = '[', 1)[1], '_') if (emb.names != Key(object = value)){ colnames( slot(object = value, name = 'cell.embeddings') ) <- gsub(pattern = emb.names, replacement = Key(object = value), colnames(Embeddings(object = value)) ) } if (!is.null(colnames(Loadings(object = value)))) { loadings.names <- paste0(sapply( X = strsplit( x = colnames(Loadings(object = value)), split = '_'), FUN = '[', 1)[1], '_') if (loadings.names != Key(object = value)) { colnames( slot(object = value, name = 'feature.loadings') ) <- gsub(pattern = loadings.names, replacement = Key(object = value), colnames(Loadings(object = value)) ) } } slot(object = x, name = 'reductions')[[i]] <- value slot(object = x, name = 'reductions') <- Filter( f = Negate(f = is.null), x = slot(object = x, name = 'reductions') ) # check column names # Validate and return validObject(object = x) return(x) } ) #' @rdname cash-.Seurat #' #' @importFrom methods selectMethod #' setMethod( f = '[[<-', signature = c(x = 'Seurat', i = 'character', j = 'missing', value = 'factor'), definition = function(x, i, ..., value) { # Add multiple objects if (length(x = i) > 1L) { value <- rep_len(x = value, length.out = length(x = i)) for (idx in seq_along(along.with = i)) { x[[i[idx]]] <- value[[idx]] } return(x) } objs <- .FilterObjects( object = x, classes.keep = c( 'Assay', 'StdAssay', 'DimReduc', 'Graph', 'Neighbor', 'SeuratCommand', 'SpatialImage' ) ) if (i %in% objs) { cls <- class(x = x[[i]])[1L] abort(message = paste( sQuote(x = i, q = FALSE), "already exists as", ifelse( test = tolower(x = substr(x = cls, start = 1, stop = 1)) %in% .Vowels(), yes = 'an', no = 'a' ), class(x = x[[i]])[1L] )) } # fast way to add column if (length(x = value) == ncol(x = x) && all(names(x = value) == colnames(x = x))) { slot(object = x, name = 'meta.data')[,i] <- value return(x) } # Add a column of cell-level meta data if (is.null(x = names(x = value))) { # Handle cases where new meta data is unnamed value <- rep_len(x = value, length.out = ncol(x = x)) names(x = value) <- colnames(x = x) } else { # Check cell names for new objects names.intersect <- intersect(x = names(x = value), y = colnames(x = x)) if (!length(x = names.intersect)) { stop( "No cell overlap between new meta data and Seurat object", call. = FALSE ) } value <- value[names.intersect] } df <- EmptyDF(n = ncol(x = x)) row.names(x = df) <- colnames(x = x) df[[i]] <- factor(x = NA, levels = levels(x = value)) # df[[i]] <- if (i %in% names(x = x[[]])) { # x[[i, na.rm = FALSE]] # } else { # factor(x = NA, levels = levels(x = value)) # } df[names(x = value), i] <- value slot(object = x, name = 'meta.data')[, i] <- df[[i]] validObject(object = x) return(x) } ) #' @rdname sub-subset-Seurat #' setMethod( f = '[[<-', signature = c(x = 'Seurat', i = 'character', j = 'missing', value = 'Graph'), definition = function(x, i, ..., value) { validObject(object = value) i <- make.names(names = i) # Checks for if the Graph or name already exists if (i %in% names(x = x)) { if (!inherits(x = x[[i]], what = 'Graph')) { abort( message = paste( sQuote(i), "already exists as an object of class", class(x = x[[i]])[1L] ), class = 'duplicateError' ) } if (!identical(x = class(x = value), y = class(x = x[[i]]))) { warning( "Graph ", i, " changing from ", class(x = x[[i]]), " to ", class(x = value), call. = FALSE, immediate. = TRUE ) } if (!all(dim(x = value) == dim(x = x[[i]]))) { warning( "Different cells from existing graph ", i, call. = FALSE, immediate. = TRUE ) } } # Check cells gcells <- Cells(x = value, margin = NA_integer_) if (!all(gcells %in% colnames(x = x))) { stop("Cannot add cells with [[<-", call. = FALSE) } cell.order <- MatchCells( new = gcells, orig = colnames(x = x), ordered = TRUE ) # TODO: enable reordering cells in graph if (is.unsorted(x = cell.order)) { stop("Cannot add graphs with unordered cells", call. = FALSE) validObject(object = value) } # Add the graph slot(object = x, name = 'graphs')[[i]] <- value slot(object = x, name = 'graphs') <- Filter( f = Negate(f = is.null), x = slot(object = x, name = 'graphs') ) # Validate and return validObject(object = x) return(x) } ) #' @rdname cash-.Seurat #' setMethod( f = '[[<-', signature = c(x = 'Seurat', i = 'character', j = 'missing', value = 'list'), definition = function(x, i, ..., value) { # Because R is stupid sometimes if (!length(x = i) && !length(x = value)) { return(x) } # Check that the `i` we're adding are present in the list if (!is.null(x = names(x = value))) { i <- arg_match(arg = i, values = names(x = value), multiple = TRUE) } else if (length(x = i) != length(x = value)) { abort(message = paste( "Cannot assing", length(x = i), "names to", length(x = value), "bits of meta data" )) } else { names(x = value) <- i } # Add the meta data for (n in i) { x[[n]] <- value[[n]] } return(x) } ) #' @rdname cash-.Seurat #' setMethod( f = '[[<-', signature = c(x = 'Seurat', i = 'missing', j = 'missing', value = 'list'), definition = function(x, i, ..., value) { stopifnot(IsNamedList(x = value)) for (y in names(x = value)) { x[[y]] <- value[[y]] } return(x) } ) #' @rdname sub-subset-Seurat #' setMethod( f = '[[<-', signature = c( x = 'Seurat', i = 'character', j = 'missing', value = 'Neighbor' ), definition = function(x, i, ..., value) { validObject(object = value) i <- make.names(names = i) # Checks for if the Neighbor or name already exists if (i %in% .Subobjects(object = x)) { if (!inherits(x = x[[i]], what = 'Neighbor')) { abort( message = paste( sQuote(i), "already exists as an object of class", class(x = x[[i]])[1L] ), class = 'duplicateError' ) } if (!identical(x = class(x = value), y = class(x = x[[i]]))) { warn(message = paste( "Graph", i, "changing from", class(x = x[[i]])[1L], "to", class(x = value)[1L] )) } if (length(x = Cells(x = value)) != length(x = Cells(x = x[[i]]))) { warn(message = paste( "Number of cells changing from", length(x = Cells(x = x[[i]])), "to", length(x = Cells(x = value)) )) } } # Check for cells if (!all(Cells(x = value) %in% colnames(x = x))) { abort(message = "Cannot add new cells with [[<-") } cell.order <- MatchCells( new = Cells(x = value), orig = colnames(x = x), ordered = TRUE ) # TODO: enable reordering cells in Neighbors if (is.unsorted(x = cell.order)) { abort(message = "Cannot add Neighbors with unordered cells") validObject(object = value) } slot(object = x, name = 'neighbors')[[i]] <- value slot(object = x, name = 'neighbors') <- Filter( f = Negate(f = is.null), x = slot(object = x, name = 'neighbors') ) # Validate and return validObject(object = x) return(x) } ) #' Remove Subobjects and Cell-Level Meta Data #' #' @inheritParams [[<-,Seurat #' @param i Name(s) of subobject(s) or cell-level meta data to remove #' @param value NULL #' #' @return \code{x} with \code{i} removed from the object #' #' @name [[<-,Seurat,NULL #' @rdname sub-subset-Seurat-NULL #' #' @family seurat #' #' @seealso See \link[=[[.Seurat]{here} for pulling subobjects using \code{[[}, #' \link[=$.Seurat]{here} for adding metadata with \code{[[<-}, and #' \link[=[[<-,Seurat]{here} for adding subobjects with \code{[[<-} #' #' @aliases remove-object remove-objects \S4method{[[<-}{Seurat,character,missing,NULL} #' NULL #' @rdname sub-subset-Seurat-NULL #' setMethod( f = '[[<-', signature = c(x = 'Seurat', i = 'character', j = 'missing', value = 'NULL'), definition = function(x, i, ..., value) { # Allow removing multiple objects or bits of cell-level meta data at once for (name in i) { # Determine the slot to use # If no subobject found, check cell-level meta data slot.use <- .FindObject(object = x, name = name) %||% 'meta.data' switch( EXPR = slot.use, 'meta.data' = { # If we can't find the cell-level meta data, throw a warning and move # to the next name if (!name %in% names(x = x[[]])) { warn(message = paste( "Cannot find cell-level meta data named ", name )) next } # Remove the column of meta data slot(object = x, name = 'meta.data')[, name] <- value }, 'assays' = { # Cannot remove the default assay if (isTRUE(x = name == DefaultAssay(object = x))) { stop("Cannot delete default assay", call. = FALSE) } # Remove the assay slot(object = x, name = slot.use)[[i]] <- value }, # Remove other subobjects slot(object = x, name = slot.use)[[name]] <- value ) } # Validate and return validObject(object = x) return(x) } ) #' @rdname sub-subset-Seurat #' setMethod( f = '[[<-', signature = c( x = 'Seurat', i = 'character', j = 'missing', value = 'SeuratCommand' ), definition = function(x, i, ..., value) { validObject(object = value) i <- make.names(names = i) # Checks for if the SeuratCommand or name already exists if (i %in% .Subobjects(object = x)) { if (!inherits(x = x[[i]], what = 'SeuratCommand')) { abort( message = paste( sQuote(i), "already exists as an object of class", class(x = x[[i]])[1L] ), class = 'duplicateError' ) } if (!identical(x = class(x = value), y = class(x = x[[i]]))) { warn(message = paste( "Command", i, "changing from", class(x = x[[i]])[1L], "to", class(x = value)[1L] )) } } if (is.null(x = DefaultAssay(object = value))) { warn(message = "Adding a command log without an assay associated with it") } # Ensure the command gets put at the end of the list # slot(object = x, name = 'commands')[[i]] <- NULL suppressWarnings(expr = x[[i]] <- NULL) slot(object = x, name = 'commands')[[i]] <- value slot(object = x, name = 'commands') <- Filter( f = Negate(f = is.null), x = slot(object = x, name = 'commands') ) # Validate and return validObject(object = x) return(x) } ) #' @rdname sub-subset-Seurat #' setMethod( f = '[[<-', signature = c( x = 'Seurat', i = 'character', j = 'missing', value = 'SpatialImage' ), definition = function(x, i, ..., value) { validObject(object = value) i <- make.names(names = i) # Checks for if the image or name already exists if (i %in% .Subobjects(object = x)) { if (!inherits(x = x[[i]], what = 'SpatialImage')) { abort( message = paste( sQuote(i), "already exists as an object of class", class(x = x[[i]])[1L] ), class = 'duplicateError' ) } if (!identical(x = class(x = value), y = class(x = x[[i]]))) { warn(message = paste( "Image", i, "changing from", class(x = x[[i]])[1L], "to", class(x = value)[1L] )) } } # Check cells if (!all(Cells(x = value) %in% colnames(x = x))) { abort(message = "Cannot add new cells with [[<-") } cell.order <- MatchCells( new = Cells(x = value), orig = colnames(x = x), ordered = TRUE ) if (is.unsorted(x = cell.order)) { warn(message = "Adding image with unordered cells") } # Check assay if (!DefaultAssay(object = value) %in% Assays(object = x)) { warn(message = "Adding image data that isn't associated with any assays") } # Check keys Key(object = value) <- .CheckKey( key = Key(object = value), existing = Key(object = x), name = i ) slot(object = x, name = 'images')[[i]] <- value slot(object = x, name = 'images') <- Filter( f = Negate(f = is.null), x = slot(object = x, name = 'images') ) # Validate and return validObject(object = x) return(x) } ) #' @inherit [[<-,Seurat #' #' @keywords internal #' setMethod( f = '[[<-', signature = c( x = 'Seurat', i = 'character', j = 'missing', value = 'StdAssay' ), definition = function(x, i, ..., value) { # Reuse the `value = Assay` method fn <- slot( object = selectMethod( f = '[[<-', signature = c( x = 'Seurat', i = 'character', j = 'missing', value = 'Assay' ) ), name = '.Data' ) cell.order <- MatchCells( new = colnames(x = value), orig = colnames(x = x), ordered = TRUE ) if (is.unsorted(cell.order)) { value.order <- new( Class = 'Assay5', layers = list(), default = 0L, features = value@features, cells = LogMap(colnames(value)[cell.order]), meta.data = value@meta.data, misc = value@misc ) for (l in Layers(object = value)) { LayerData(object = value.order, layer = l) <- LayerData(object = value, layer = l) } value <- value.order } return(fn(x = x, i = i, value = value)) } ) #' @rdname cash-.Seurat #' setMethod( f = '[[<-', signature = c( x = 'Seurat', i = 'character', j = 'missing', value = 'vector' ), definition = function(x, i, ..., value) { # Add multiple objects if (length(x = i) > 1L) { value <- rep_len(x = value, length.out = length(x = i)) for (idx in seq_along(along.with = i)) { x[[i[idx]]] <- value[[idx]] } return(x) } objs <- .FilterObjects( object = x, classes.keep = c( 'Assay', 'StdAssay', 'DimReduc', 'Graph', 'Neighbor', 'SeuratCommand', 'SpatialImage' ) ) if (i %in% objs) { cls <- class(x = x[[i]])[1L] abort(message = paste( sQuote(x = i, q = FALSE), "already exists as", ifelse( test = tolower(x = substr(x = cls, start = 1, stop = 1)) %in% .Vowels(), yes = 'an', no = 'a' ), class(x = x[[i]])[1L] )) } # fast way to add column if (length(x = value) == ncol(x = x) && all(names(x = value) == colnames(x = x))) { slot(object = x, name = 'meta.data')[,i] <- value return(x) } # Add a column of cell-level meta data if (is.null(x = names(x = value))) { # Handle cases where new meta data is unnamed value <- rep_len(x = value, length.out = ncol(x = x)) names(x = value) <- colnames(x = x) } else { # Check cell names for new objects names.intersect <- intersect(x = names(x = value), y = colnames(x = x)) if (!length(x = names.intersect)) { stop( "No cell overlap between new meta data and Seurat object", call. = FALSE ) } value <- value[names.intersect] } df <- EmptyDF(n = ncol(x = x)) row.names(x = df) <- colnames(x = x) df[[i]] <- if (i %in% names(x = x[[]])) { if (is.character(x = value)) { as.character(x = x[[i, drop = TRUE, na.rm = FALSE]]) } else { as.vector(x = x[[i, drop = TRUE, na.rm = FALSE]]) } } else { NA } df[names(x = value), i] <- value slot(object = x, name = 'meta.data')[, i] <- df[[i]] validObject(object = x) return(x) } ) #' Row and Column Sums and Means #' #' Calculate \code{\link{rowSums}}, \code{\link{colSums}}, #' \code{\link{rowMeans}}, and \code{\link{colMeans}} on #' \code{\link{Seurat}} objects #' #' @inheritParams .DollarNames.Seurat #' @inheritParams Matrix::colMeans #' @param slot Name of assay expression matrix to calculate column/row #' means/sums on #' #' @return \code{colMeans}: the column (cell-wise) means of \code{slot} #' #' @importFrom Matrix colMeans #' #' @keywords internal #' #' @export #' #' @concept seurat #' #' @seealso \code{\link{Seurat}} #' #' @examples #' head(colMeans(pbmc_small)) #' setMethod( f = 'colMeans', signature = c('x' = 'Seurat'), definition = function(x, na.rm = FALSE, dims = 1, ..., slot = 'data') { return(colMeans( x = LayerData(object = x, layer = slot), na.rm = na.rm, dims = dims, ... )) } ) #' @return \code{colSums}: the column (cell-wise) sums of \code{slot} #' #' @rdname colMeans-Seurat-method #' #' @importFrom Matrix colSums #' #' @export #' #' @examples #' head(colSums(pbmc_small)) #' setMethod( f = 'colSums', signature = c('x' = 'Seurat'), definition = function(x, na.rm = FALSE, dims = 1, ..., slot = 'data') { return(Matrix::colSums( x = LayerData(object = x, layer = slot), na.rm = na.rm, dims = dims, ... )) } ) #' @importFrom methods initialize #' setMethod( f = 'initialize', signature = 'Seurat', definition = function( .Object, assays = list(), meta.data = NULL, active.assay = character(length = 0L), active.ident = NULL, graphs = list(), neighbors = list(), reductions = list(), images = list(), project.name = getOption( x = 'Seurat.object.project', default = Seurat.options$Seurat.object.project ), misc = list(), version = packageVersion(pkg = 'SeuratObject'), commands = list(), tools = list(), ... ) { # Initialize the object .Object <- callNextMethod(.Object, ...) # Set defaults for meta data and idents cells <- Reduce(f = union, x = lapply(X = assays, FUN = Cells)) if (is.null(x = meta.data)) { meta.data <- EmptyDF(n = length(x = cells)) row.names(x = meta.data) <- cells } if (is.null(x = active.ident)) { active.ident <- factor(x = cells) } # Add slots slot(object = .Object, name = 'assays') <- assays slot(object = .Object, name = 'meta.data') <- meta.data slot(object = .Object, name = 'active.assay') <- active.assay slot(object = .Object, name = 'active.ident') <- active.ident slot(object = .Object, name = 'graphs') <- graphs slot(object = .Object, name = 'neighbors') <- neighbors slot(object = .Object, name = 'reductions') <- reductions slot(object = .Object, name = 'images') <- images slot(object = .Object, name = 'project.name') <- project.name slot(object = .Object, name = 'misc') <- misc slot(object = .Object, name = 'version') <- version slot(object = .Object, name = 'commands') <- commands slot(object = .Object, name = 'tools') <- tools # Validate the object validObject(object = .Object) # Return return(.Object) } ) #' @return \code{rowMeans}: the row (feature-wise) means of \code{slot} #' #' @rdname colMeans-Seurat-method #' #' @importFrom Matrix colSums #' #' @export #' #' @examples #' head(rowMeans(pbmc_small)) #' setMethod( f = 'rowMeans', signature = c('x' = 'Seurat'), definition = function(x, na.rm = FALSE, dims = 1, ..., slot = 'data') { return(Matrix::rowMeans( x = LayerData(object = x, layer = slot), na.rm = na.rm, dims = dims, ... )) } ) #' @return \code{rowSums}: the row (feature-wise) sums of \code{slot} #' #' @rdname colMeans-Seurat-method #' #' @importFrom Matrix rowSums #' #' @export #' #' @examples #' head(rowSums(pbmc_small)) #' setMethod( f = 'rowSums', signature = c('x' = 'Seurat'), definition = function(x, na.rm = FALSE, dims = 1, ..., slot = 'data') { return(Matrix::rowSums( x = LayerData(object = x, layer = slot), na.rm = na.rm, dims = dims, ... )) } ) #' Seurat Object Overview #' #' Overview of a \code{\link{Seurat}} object #' #' @template return-show #' #' @keywords internal #' #' @concept seurat #' #' @examples #' pbmc_small #' setMethod( f = "show", signature = "Seurat", definition = function(object) { #object <- UpdateSlots(object = object) x <- tryCatch( expr = slot(object = object, name = 'images'), error = function(...) {stop("Please run UpdateSeuratObject on your object", call. = FALSE)}) assays <- .FilterObjects(object = object, classes.keep = c('Assay', 'StdAssay')) nfeatures <- sum(vapply( X = assays, FUN = function(x) { return(nrow(x = object[[x]])) }, FUN.VALUE = numeric(length = 1L) )) num.assays <- length(x = assays) cat("An object of class", class(x = object), "\n") cat( nfeatures, 'features across', ncol(x = object), 'samples within', num.assays, ifelse(test = num.assays == 1, yes = 'assay', no = 'assays'), "\n" ) cat( "Active assay:", DefaultAssay(object = object), paste0( '(', nrow(x = object), ' features, ', length(x = suppressWarnings(expr = VariableFeatures(object = object))), ' variable features)' ) ) cat( '\n', length(x = Layers(object = object)), ifelse( test = length(x = Layers(object = object)) == 1L, yes = 'layer', no = 'layers' ), 'present:', strwrap(x = paste(Layers(object = object), collapse = ', ')) ) other.assays <- assays[assays != DefaultAssay(object = object)] if (length(x = other.assays) > 0) { cat( '\n', length(x = other.assays), 'other', ifelse(test = length(x = other.assays) == 1, yes = 'assay', no = 'assays'), 'present:', strwrap(x = paste(other.assays, collapse = ', ')) ) } reductions <- .FilterObjects(object = object, classes.keep = 'DimReduc') if (length(x = reductions) > 0) { cat( '\n', length(x = reductions), 'dimensional', ifelse(test = length(x = reductions) == 1, yes = 'reduction', no = 'reductions'), 'calculated:', strwrap(x = paste(reductions, collapse = ', ')) ) } fovs <- .FilterObjects(object = object, classes.keep = 'FOV') if (length(x = fovs)) { cat( '\n', length(x = fovs), 'spatial', ifelse(test = length(x = fovs) == 1L, yes = 'field', no = 'fields'), 'of view present:', strwrap(x = paste(fovs, sep = ', ')) ) } images <- .FilterObjects(object = object, classes.keep = 'SpatialImage') images <- setdiff(x = images, y = fovs) if (length(x = images)) { cat( '\n', length(x = images), ifelse(test = length(x = images) == 1L, yes = 'image', no = 'images'), 'present:', strwrap(x = paste(images, collapse = ', ')) ) } cat('\n') } ) #' Old Seurat Object Overview #' #' Overview of a \code{\link[=oldseurat]{seurat}} object overview #' #' @param object An old seurat object #' #' @template return-show #' #' @rdname show-oldseurat-method #' #' @keywords internal #' #' @concept oldseurat #' setMethod( f = 'show', signature = 'seurat', definition = function(object) { cat( "An old seurat object\n", nrow(x = object@data), 'genes across', ncol(x = object@data), 'samples\n' ) } ) #' Seurat Object Validity #' #' @templateVar cls Seurat #' @template desc-validity #' #' @name Seurat-validity #' #' @family seurat #' #' @seealso \code{\link[methods]{validObject}} #' setValidity( Class = 'Seurat', method = function(object) { if (.GetSeuratCompat() < '5.0.0') { return(TRUE) } if (isFALSE(x = getOption(x = "Seurat.object.validate", default = TRUE))) { warn( message = paste("Not validating", class(x = object)[1L], "objects"), class = 'validationWarning' ) return(TRUE) } valid <- NULL # TODO: Check meta data md <- slot(object = object, name = 'meta.data') # if (length(x = class(x = md)) != 1L || class(x = md) != 'data.frame') { if (!.IsDataFrame(x = md)) { valid <- c(valid, "'meta.data' must be a base-R data.frame") } if (ncol(x = md)) { if (is.null(x = names(x = md)) || any(!nzchar(x = names(x = md)))) { valid <- c(valid, "all columns in 'meta.data' must be named") } } # TODO: Check cells ocells <- colnames(x = object) if (anyDuplicated(x = ocells)) { valid <- c(valid, "cell names may not be duplicated") } # TODO: Check assays if (!IsNamedList(x = slot(object = object, name = 'assays'))) { valid <- c(valid, "'assays' must be a named list") } else { for (assay in Assays(object = object)) { if (!inherits(x = object[[assay]], what = c('Assay', 'StdAssay'))) { valid <- c(valid, "'assays' must be a list of 'Assay' objects") break } acells <- colnames(x = object[[assay]]) if (!all(acells %in% ocells)) { valid <- c(valid, "all cells in assays must be present in the Seurat object") } else if (is.unsorted(x = MatchCells(new = acells, orig = ocells, ordered = TRUE))) { valid <- c( valid, "all cells in assays must be in the same order as the Seurat object" ) } if (!isTRUE(x = nzchar(x = Key(object = object[[assay]])))) { valid <- c(valid, "all assays must have a key") } } } # TODO: Check reductions if (!IsNamedList(x = slot(object = object, name = 'reductions'), pass.zero = TRUE)) { valid <- c(valid, "'reductions' must be a named list") } else { for (reduc in Reductions(object = object)) { # Check cells rcells <- Cells(x = object[[reduc]]) if (!all(rcells %in% ocells)) { valid <- c(valid, "All cells in reductions must be present in the Seurat object") } else if (is.unsorted(x = MatchCells(new = rcells, orig = ocells, ordered = TRUE))) { valid <- c(valid, "all cells in reductions must be in the same order as the Seurat object") } # TODO: Check features # TODO: Check default assay } } # Check graphs if (!IsNamedList(x = slot(object = object, name = 'graphs'), pass.zero = TRUE)) { valid <- c(valid, "'graphs' must be a named list") } else { for (graph in Graphs(object = object)) { gnames <- Cells(x = object[[graph]], margin = NA_integer_) # if (!DefaultAssay(object = object[[graph]]) %in% Assays(object = object)) { # valid <- c( # valid, # "the default assay for graphs must be present in the Seurat object" # ) # } if (!all(gnames %in% colnames(x = object))) { valid <- c(valid, "all cells in graphs must be present in the Seurat object") } else if (is.unsorted(x = MatchCells(new = gnames, orig = ocells, ordered = TRUE))) { valid <- c( valid, paste0( "all cells in graphs must be in the same order as the Seurat object (offending: ", graph, ")" ) ) } } } # Check neighbors if (!IsNamedList(x = slot(object = object, name = 'neighbors'), pass.zero = TRUE)) { valid <- c(valid, "'neighbors' must be a named list") } else { for (nn in Neighbors(object = object)) { ncells <- Cells(x = object[[nn]]) if (!all(ncells %in% ocells)) { valid <- c(valid, "All cells in neighbor objects must be present in the Seurat object") } else if (is.unsorted(x = MatchCells(new = ncells, orig = ocells, ordered = TRUE))) { valid <- c(valid, "All cells in neighbor objects must be in the same order as the Seurat object") } } } # Check images if (!IsNamedList(x = slot(object = object, name = 'images'), pass.zero = TRUE)) { valid <- c(valid, "'images' must be a named list") } else { for (img in Images(object = object)) { icells <- Cells(x = object[[img]]) if (!all(icells %in% ocells)) { valid <- c(valid, "All cells in images must be present in the Seurat object") } # else if (is.unsorted(x = MatchCells(new = icells, orig = ocells, ordered = TRUE))) { # valid <- c(valid, "All cells in images must be in the same order as the Seurat object") # } } } # TODO: Check project proj <- Project(object = object) if (length(x = proj) != 1L) { valid <- c(valid, "'project' must be a 1-length character vector") } else if (is.na(x = proj)) { valid <- c(valid, "'project' cannot be NA") } else if (!nzchar(x = proj)) { valid <- c(valid, "'project' cannot be an empty character") } # TODO: Check idents idents <- Idents(object = object) if (length(x = idents) != ncol(x = object)) { valid <- c( valid, "'active.idents' must be as long as the number of cells present" ) } else if (!all(names(x = idents) == colnames(x = object))) { valid <- c(valid, "'active.idents' must be named with cell names") } # TODO: Check version if (length(x = slot(object = object, name = 'version')) > 1) { valid <- c(valid, "Only one version is allowed") } return(valid %||% TRUE) } ) #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Internal #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% .FilterCells <- function(object, validate = TRUE) { objs <- .FilterObjects( object = object, classes.keep = c( 'Assay', # assays 'StdAssay', # assays 'Graph', # graphs 'Neighbor', # neighbors 'DimReduc', # reductions 'SpatialImage' # images ) ) '' } .SubobjectAssign <- function() { classes <- slot( object = methods::findMethods(f = '[[<-', classes = 'Seurat'), name = 'signatures' ) classes <- Filter(f = function(x) x[1] == 'Seurat', x = classes) classes <- vapply( X = classes, FUN = function(x) { return(x[length(x = x)]) }, FUN.VALUE = character(length = 1L) ) classes <- unique(x = classes) classes <- setdiff( x = classes, y = c('Seurat', 'ANY', 'NULL', 'vector', 'list', 'StdAssay') ) classes <- Filter( f = function(x) { cdef <- methods::getClass(Class = x) return(!'oldClass' %in% names(x = slot(object = cdef, name = 'contains'))) }, x = classes ) } #' Object Collections #' #' Find the names of collections in an object #' #' @param object An S4 object #' #' @return A vector with the names of slots that are a list #' #' @keywords internal #' #' @noRd #' #' @examples #' \donttest{ #' SeuratObject:::Collections(pbmc_small) #' } #' Collections <- function(object) { if (!isS4(object)) { return(NULL) } collections <- vapply( X = slotNames(x = object), FUN = function(x) { return(inherits(x = slot(object = object, name = x), what = 'list')) }, FUN.VALUE = logical(length = 1L) ) collections <- Filter(f = isTRUE, x = collections) return(names(x = collections)) } #' Get the default image of an object #' #' Attempts to find all images associated with the default assay of the object. #' If none present, finds all images present in the object. Returns the name of #' the first image #' #' @param object A \code{\link{Seurat}} object #' #' @return The name of the default image #' #' @keywords internal #' #' @noRd #' DefaultImage <- function(object) { object <- UpdateSlots(object = object) images <- Images(object = object, assay = DefaultAssay(object = object)) if (length(x = images) < 1) { images <- Images(object = object) } return(images[[1]]) } #' Find the collection of an object within a Seurat object #' #' @param object A \code{\link{Seurat}} object #' @param name Name of object to find #' #' @return The collection (slot) of the object #' #' @keywords internal #' #' @noRd #' #' @examples #' \donttest{ #' SeuratObject:::FindObject(pbmc_small, name = "RNA") #' } #' FindObject <- function(object, name) { collections <- c( 'assays', 'graphs', 'neighbors', 'reductions', 'commands', 'images' ) object.names <- lapply( X = collections, FUN = function(x) { return(names(x = slot(object = object, name = x))) } ) names(x = object.names) <- collections object.names <- Filter(f = Negate(f = is.null), x = object.names) for (i in names(x = object.names)) { if (name %in% names(x = slot(object = object, name = i))) { return(i) } } return(NULL) } #' Update Seurat v2 Internal Objects #' #' Helper functions to update old Seurat v2 objects to v3/v4 objects #' #' @param old.assay,old.dr,old.jackstraw Seurat v2 assay, dimensional #' reduction, or jackstraw object #' @param assay Name to store for assay in new object #' #' @return A v3/v4 \code{\link{Assay}}, \code{\link{DimReduc}}, or #' \code{\link{JackStrawData}} object #' #' @name V2Update #' @rdname V2Update #' #' @keywords internal #' #' @noRd #' UpdateAssay <- function(old.assay, assay) { if (!is.null(x = old.assay@data)) { cells <- colnames(x = old.assay@data) } else { cells <- colnames(x = old.assay@raw.data) } counts <- old.assay@raw.data data <- old.assay@data if (!inherits(x = counts, what = 'dgCMatrix')) { counts <- as.sparse(x = as.matrix(x = counts)) } if (!is.null(x = data)) { if (!inherits(x = data, what = 'dgCMatrix')) { data <- as.sparse(x = as.matrix(x = data)) } } else { data <- as.sparse( x = Matrix( data = 0, nrow = nrow(x = counts), ncol = ncol(x = counts), dimnames = dimnames(x = counts) ), ) } if (!inherits(x = old.assay@scale.data, what = 'matrix')) { scale.data <- new(Class = 'matrix') } else { scale.data <- old.assay@scale.data } new.assay <- new( Class = 'Assay', counts = counts[, cells], data = data, scale.data = scale.data, meta.features = data.frame(row.names = rownames(x = counts)), var.features = old.assay@var.genes, key = paste0(assay, "_") ) return(new.assay) } #' @param assay.used Name of assay used to compute dimension reduction #' #' @importFrom methods new #' #' @rdname V2Update #' #' @noRd #' UpdateDimReduction <- function(old.dr, assay) { new.dr <- list() for (i in names(x = old.dr)) { cell.embeddings <- old.dr[[i]]@cell.embeddings %||% new(Class = 'matrix') feature.loadings <- old.dr[[i]]@gene.loadings %||% new(Class = 'matrix') stdev <- old.dr[[i]]@sdev %||% numeric() misc <- old.dr[[i]]@misc %||% list() new.jackstraw <- UpdateJackstraw(old.jackstraw = old.dr[[i]]@jackstraw) old.key <- old.dr[[i]]@key if (length(x = old.key) == 0) { old.key <- gsub(pattern = "(.+?)(([0-9]+).*)", replacement = "\\1", x = colnames(cell.embeddings)[[1]]) if (length(x = old.key) == 0) { old.key <- i } } new.key <- suppressWarnings(expr = UpdateKey(key = old.key)) colnames(x = cell.embeddings) <- gsub( pattern = old.key, replacement = new.key, x = colnames(x = cell.embeddings) ) colnames(x = feature.loadings) <- gsub( pattern = old.key, replacement = new.key, x = colnames(x = feature.loadings) ) new.dr[[i]] <- new( Class = 'DimReduc', cell.embeddings = as(object = cell.embeddings, Class = 'matrix'), feature.loadings = as(object = feature.loadings, Class = 'matrix'), assay.used = assay, stdev = as(object = stdev, Class = 'numeric'), key = as(object = new.key, Class = 'character'), jackstraw = new.jackstraw, misc = as(object = misc, Class = 'list') ) } return(new.dr) } #' @importFrom methods .hasSlot new #' #' @rdname V2Update #' #' @keywords internal #' #' @noRd #' UpdateJackstraw <- function(old.jackstraw) { if (is.null(x = old.jackstraw)) { new.jackstraw <- new( Class = 'JackStrawData', empirical.p.values = new(Class = 'matrix'), fake.reduction.scores = new(Class = 'matrix'), empirical.p.values.full = new(Class = 'matrix'), overall.p.values = new(Class = 'matrix') ) } else { if (.hasSlot(object = old.jackstraw, name = 'overall.p.values')) { overall.p <- old.jackstraw@overall.p.values %||% new(Class = 'matrix') } else { overall.p <- new(Class = 'matrix') } new.jackstraw <- new( Class = 'JackStrawData', empirical.p.values = old.jackstraw@emperical.p.value %||% new(Class = 'matrix'), fake.reduction.scores = old.jackstraw@fake.pc.scores %||% new(Class = 'matrix'), empirical.p.values.full = old.jackstraw@emperical.p.value.full %||% new(Class = 'matrix'), overall.p.values = overall.p ) } return(new.jackstraw) } SeuratObject/R/neighbor.R0000644000176200001440000001153414473173564015007 0ustar liggesusers#' @include zzz.R #' @include generics.R #' @importFrom methods new slot slot<- #' NULL #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Class definitions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' The Neighbor class #' #' The Neighbor class is used to store the results of neighbor finding #' algorithms #' #' @slot nn.idx Matrix containing the nearest neighbor indices #' @slot nn.dist Matrix containing the nearest neighbor distances #' @slot alg.idx The neighbor finding index (if applicable). E.g. the annoy #' index #' @slot alg.info Any information associated with the algorithm that may be #' needed downstream (e.g. distance metric used with annoy is needed when #' reading in from stored file). #' @slot cell.names Names of the cells for which the neighbors have been #' computed. #' #' @name Neighbor-class #' @rdname Neighbor-class #' @exportClass Neighbor #' Neighbor <- setClass( Class = 'Neighbor', slots = c( nn.idx = 'matrix', nn.dist = 'matrix', alg.idx = 'ANY', alg.info = 'list', cell.names = 'character' ) ) #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Functions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for Seurat-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' @rdname as.Neighbor #' @export #' @method as.Neighbor Graph #' as.Neighbor.Graph <- function(x, ...) { nn.mats <- GraphToNeighborHelper(mat = x) return(Neighbor( nn.idx = nn.mats[[1]], nn.dist = nn.mats[[2]], cell.names = rownames(x = x) )) } #' @rdname Cells #' @method Cells Neighbor #' @export #' Cells.Neighbor <- function(x, ...) { return(slot(object = x, name = "cell.names")) } #' @rdname Distances #' @export #' @method Distances Neighbor #' Distances.Neighbor <- function(object, ...) { object <- UpdateSlots(object = object) distances <- slot(object = object, name = "nn.dist") rownames(x = distances) <- slot(object = object, name = "cell.names") return(distances) } #' @rdname NNIndex #' @export #' @method Index Neighbor #' Index.Neighbor <- function(object, ...) { object <- UpdateSlots(object = object) index <- slot(object = object, name = "alg.idx") if (is.null(x = index)) { return(NULL) } else if (IsNullPtr(x = index$.pointer)) { return(NULL) } return(index) } #' @rdname NNIndex #' @export #' @method Index<- Neighbor #' "Index<-.Neighbor" <- function(object, ..., value) { CheckDots(...) slot(object = object, name = "alg.idx") <- value return(object) } #' @rdname Indices #' @export #' @method Indices Neighbor #' Indices.Neighbor <- function(object, ...) { object <- UpdateSlots(object = object) indices <- slot(object = object, name = "nn.idx") rownames(x = indices) <- slot(object = object, name = "cell.names") return(indices) } #' @param old.names vector of old cell names #' @rdname RenameCells #' @export #' @method RenameCells Neighbor #' RenameCells.Neighbor <- function( object, old.names = NULL, new.names = NULL, ... ) { CheckDots(...) neighbor.names <- Cells(x = object) names(x = new.names) <- old.names slot(object = object, name = "cell.names") <- unname(obj = new.names[neighbor.names]) return(object) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for R-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' \code{Neighbor} Methods #' #' Methods for \code{\link{Neighbor}} objects for generics defined in #' other packages #' #' @param x,object A \code{\link{Neighbor}} object #' #' @name Neighbor-methods #' @rdname Neighbor-methods #' #' @concept neighbor #' NULL #' @describeIn Neighbor-methods Dimensions of the neighbor indices #' #' @return \code{dim} Dimensions of the indices matrix #' #' @export #' @method dim Neighbor #' dim.Neighbor <- function(x) { return(dim(x = Indices(object = x))) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # S4 methods #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' @describeIn Neighbor-methods Overview of a \code{Neighbor} object #' #' @return \code{show}: Prints summary to \code{\link[base]{stdout}} and #' invisibly returns \code{NULL} #' #' @importFrom methods show #' #' @export #' setMethod( f = 'show', signature = 'Neighbor', definition = function(object) { cat( "A Neighbor object containing the", ncol(x = object), "nearest neighbors for", nrow(x = object), "cells" ) } ) #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Internal #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% SeuratObject/R/default.R0000644000176200001440000001620414520004144014611 0ustar liggesusers#' @include zzz.R #' @include generics.R #' NULL #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for Seurat-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' @rdname dot-AssayClass #' @method .AssayClass StdAssay #' @export #' .AssayClass.StdAssay <- function(object) { cls <- gsub( pattern = '5$|v5$', replacement = '', x = class(x = object)[1L], ignore.case = TRUE ) return(paste(cls, '(v5)')) } #' @method .MARGIN default #' @export #' .MARGIN.default <- function(x, type = c('features', 'cells'), ...) { type <- arg_match(arg = type) return(unname(obj = c(features = 1L, cells = 2L)[type])) } #' @rdname Cells #' @method Cells default #' @export #' Cells.default <- function(x, ...) { return(colnames(x = x)) } #' @rdname IsGlobal #' @method IsGlobal default #' @export #' IsGlobal.default <- function(object, ...) { return(FALSE) } #' @importFrom stats na.omit #' #' @rdname MatchCells #' @method MatchCells character #' @export #' MatchCells.character <- function(new, orig, ordered = FALSE) { cmatch <- as.vector(x = na.omit(object = match(x = orig, table = new))) if (!length(x = cmatch)) { return(NULL) } if (!isTRUE(x = ordered)) { cmatch <- sort(x = cmatch) } return(cmatch) } #' @rdname MatchCells #' @method MatchCells NULL #' @export #' MatchCells.NULL <- function(new, orig, ordered = FALSE) { return(NULL) } #' @rdname MatchCells #' @method MatchCells numeric #' @export #' MatchCells.numeric <- function(new, orig, ordered = FALSE) { new <- unique(x = new[new <= length(x = orig)]) if (!length(x = new)) { return(NULL) } if (isTRUE(x = ordered)) { new <- sort(x = new) } return(new) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for R-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Internal #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' Add Object Metadata #' #' Internal \code{\link{AddMetaData}} definition #' #' @param object An object #' @param metadata A vector, list, or data.frame with metadata to add #' @param col.name A name for meta data if not a named list or data.frame #' #' @return object with metadata added #' #' @keywords internal #' #' @noRd #' .AddMetaData <- function(object, metadata, col.name = NULL) { if (is.null(x = col.name) && (is.atomic(x = metadata) && !is.matrix(x = metadata))) { abort(message = "'col.name' must be provided for atomic meta data") } if (inherits(x = metadata, what = c('matrix', 'Matrix'))) { metadata <- as.data.frame(x = metadata) } col.name <- col.name %||% names(x = metadata) %||% colnames(x = metadata) if (is.null(x = col.name)) { abort(message = "No metadata name provided and could not infer it from metadata object") } object[[col.name]] <- metadata return(object) } #' Internal Cropping Function #' #' @inheritParams Crop #' #' @return ... #' #' @keywords internal #' #' @noRd #' .Crop <- function(object, x = NULL, y = NULL, coords = c('plot','tissue'), ...) { if (is.null(x = x) && is.null(x = y)) { return(object) } coords <- coords[1L] coords <- match.arg(arg = coords) switch( EXPR = coords, 'plot' = { cx <- 'y' cy <- 'x' }, 'tissue' = { cx <- 'x' cy <- 'y' } ) x <- range(x %||% bbox(obj = object)[cx, , drop = TRUE]) y <- range(y %||% bbox(obj = object)[cy, , drop = TRUE]) idx <- c(max = 1L, min = 2L)[[getOption( x = 'Seurat.coords.short_range', default = Seurat.options$Seurat.coords.short_range )]] if (x[1L] == x[2L]) { x[idx] <- bbox(obj = object)[cx, idx] } if (y[1L] == y[2L]) { y[idx] <- bbox(obj = object)[cy, idx] } args <- list(x, y) names(x = args) <- switch( EXPR = coords, 'plot' = c('y', 'x'), 'tissue' = c('x', 'y') ) args <- args[c('x', 'y')] df <- do.call(what = expand.grid, args = args) df <- df[c(1, 3, 4, 2), ] df$cell <- 'cell' return(Overlay(x = object, y = CreateSegmentation(coords = df))) } #' Test Finiteness of Centroids #' #' Determines if a \code{\link{Centroids}} object should be finite; for #' \code{Centroids}, this means if their \code{nsides} slot is an integer >= 3 #' #' @param x A \code{\link{Centroids}} object #' #' @return \code{TRUE} if the \code{Centroids} are finite; otherwise #' \code{FALSE} #' #' @keywords internal #' #' @noRd #' .FiniteCentroids <- function(x) { return(as.logical(x = length(x = x))) } #' Head and Tail Object Metadata #' #' Internal \code{\link[utils]{head}} and \code{\link[utils]{tail}} definitions #' #' @param x An object #' @param n Number of rows to return #' @inheritDotParams utils::head #' #' @return The first or last \code{n} rows of object metadata #' #' @keywords internal #' #' @noRd #' .head <- function(x, n = 10L, ...) { return(head(x = x[[]], n = n, ...)) } .tail <- function(x, n = 10L, ...) { return(tail(x = x[[]], n = n, ...)) } #' Miscellaneous Data #' #' Internal functions for getting and setting miscellaneous data #' #' @param object An object #' @param slot Name of miscellaneous data to get or set #' @param ... Arguments passed to other methods #' #' @return \code{.Misc}: If \code{slot} is \code{NULL}, all miscellaneous #' data, otherwise the miscellaneous data for \code{slot} #' #' @keywords internal #' #' @noRd #' .Misc <- function(object, slot = NULL, ...) { CheckDots(...) if (is.null(x = slot)) { return(slot(object = object, name = 'misc')) } return(slot(object = object, name = 'misc')[[slot]]) } #' @param value Data to add #' #' @return \code{.Misc<-}: \code{object} with \code{value} added to the #' miscellaneous data slot \code{slot} #' #' @rdname dot-Misc #' #' @noRd #' ".Misc<-" <- function(object, slot, ..., value) { CheckDots(...) if (slot %in% names(x = Misc(object = object))) { warning( "Overwriting miscellanous data for ", slot, call. = FALSE, immediate. = TRUE ) } if (is.list(x = value)) { slot(object = object, name = 'misc')[[slot]] <- c(value) } else { slot(object = object, name = 'misc')[[slot]] <- value } return(object) } .OverBbox <- function(x, y, invert = FALSE, ...) { df <- .BboxDF(x = bbox(obj = y)) df$cell <- 'cell' return(Overlay( x = x, y = CreateSegmentation(coords = df), invert = invert, ... )) } #' Internal Overlay Method #' #' @param x Query spatial object #' @param y Target spatial object #' @param ... Ignored #' #' @return \code{x} with only the components that fall within #' the bounds of \code{y} #' #' @keywords internal #' #' @noRd #' .Overlay <- function(x, y, ...) { idx <- over(x = x, y = y) idx <- idx[!is.na(x = idx)] names(x = idx) <- vapply( X = strsplit(x = names(x = idx), split = '\\.'), FUN = '[[', FUN.VALUE = character(length = 1L), 1L, USE.NAMES = FALSE ) return(x[names(x = idx)]) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # S4 methods #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% SeuratObject/R/logmap.R0000644000176200001440000004124514520004144014447 0ustar liggesusers#' @include zzz.R #' NULL #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Class definitions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' A Logical Map #' #' A simple container for storing mappings of values using logical matrices. #' Keeps track of which values (rows) are present in which observations #' (columns). \code{LogMap} objects can be created with \code{LogMap()}; #' queries can be performed with \code{[[} and observations can be added #' or removed with \code{[[<-} #' #' @slot .Data A logical matrix with at least one row #' #' @exportClass LogMap #' #' @family logmap #' setClass( Class = 'LogMap', contains = 'matrix' ) #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Functions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' @rdname LogMap-class #' #' @param y A character vector #' #' @return \code{LogMap}: A new \code{LogMap} object with zero columns and #' \code{length(x = x)} rows; rownames are set to \code{x} #' #' @export #' #' @order 1 #' #' @examples #' # Create a LogMap #' map <- LogMap(letters[1:10]) #' map #' #' # Get the names of values in the LogMap #' map[[NULL]] #' rownames(map) #' #' # Add an observation to the LogMap #' map[['obs']] <- c(1, 3, 7) #' map[['entry']] <- c(2, 7, 10) #' map #' #' # Get the names of observations in the LogMap #' colnames(map) #' #' # Fetch an observation from the LogMap #' map[['obs']] #' #' # Get the full logical matrix #' map[[]] #' #' # Remove an observation from the LogMap #' map[['obs']] <- NULL #' map[['entry']] <- NULL #' map #' LogMap <- function(y) { if (!is.character(x = y)) { y <- as.character(x = y) } return(new( Class = 'LogMap', .Data = matrix(nrow = length(x = y), ncol = 0, dimnames = list(y, NULL)) )) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for Seurat-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for R-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' Coerce Logical Maps to Matrices #' #' Coerce a logical map to a matrix; this removes all #' \link[=LogMap]{logical map} class capabilities from #' the object and returns a base-R matrix object #' #' @param x A \code{\link{LogMap}} object #' @template param-dots-ignored #' #' @return A base-R matrix created from \code{x} #' #' @method as.matrix LogMap #' @export #' #' @family logmap #' #' @examples #' map <- LogMap(letters[1:10]) #' map[['obs']] <- c(1, 3, 7) #' mat <- as.matrix(map) #' mat #' class(mat) #' as.matrix.LogMap <- function(x, ...) { return(as(object = x, Class = 'matrix')) } #' Drop Unused Logical Map Values #' #' Remove any unused values from a \link[=LogMap]{logical map} #' #' @template param-dots-ignored #' @param x A \code{LogMap} object #' #' @return \code{x} with values not present in any #' observation removed #' #' @method droplevels LogMap #' @export #' #' @family logmap #' #' @examples #' map <- LogMap(letters[1:10]) #' map[['obs']] <- c(1, 3, 7) #' map[['entry']] <- c(2, 7, 10) #' #' # Remove unused values #' map <- droplevels(map) #' map #' map[[]] #' droplevels.LogMap <- function(x, ...) { fidx <- which(x = apply( X = x, MARGIN = 1L, FUN = function(row) { return(all(vapply( X = row, FUN = isFALSE, FUN.VALUE = logical(length = 1L) ))) } )) if (length(x = fidx)) { x <- as(object = x[-fidx, , drop = FALSE], Class = 'LogMap') } validObject(object = x) return(x) } #' Find Common Logical Map Values #' #' Identify values in a \link[=LogMap]{logical map} that are #' common to every observation #' #' @inheritParams droplevels.LogMap #' @param y Ignored #' #' @return The values of \code{x} that are present in \strong{every} observation #' #' @method intersect LogMap #' @export #' #' @family logmap #' #' @examples #' map <- LogMap(letters[1:10]) #' map[['obs']] <- c(1, 3, 7) #' map[['entry']] <- c(2, 7, 10) #' #' # Identify values that are present in every observation #' intersect(map) #' intersect.LogMap <- function(x, y = missing_arg(), ...) { if (!is_missing(x = y)) { abort(message = "'y' must not be provided") } idx <- which(x = apply(X = x, MARGIN = 1L, FUN = all)) return(rownames(x = x)[idx]) } #' Find Observations by Value #' #' Identify the observations that contain a specific #' value in a \link[=LogMap]{logical map} #' #' @template param-dots-ignored #' @param object A \code{\link{LogMap}} object #' @param values A vector of values to find observations for #' @param select Observation selection method; choose from: #' \itemize{ #' \item \dQuote{\code{first}}: the first observation the value is found in #' \item \dQuote{\code{last}}: the last observation the value is found in #' \item \dQuote{\code{common}}: the first most-common observation the value #' is found in; most-common is determined by the observation that contains #' the most of the values requested #' \item \dQuote{\code{all}}: all observations the value is found in #' } #' @param simplify Simplify the resulting list to a vector #' #' @return \code{labels}: A list, or vector if \code{simplify} is \code{TRUE}, #' of all values and the observations they're found in, according #' to the value of \code{select} #' #' @method labels LogMap #' @export #' #' @family logmap #' #' @examples #' map <- LogMap(letters[1:10]) #' map[['obs']] <- c(1, 3, 7) #' map[['entry']] <- c(2, 7, 10) #' #' # Find observations for a set of values #' labels(map, c('a', 'b', 'g')) #' labels.LogMap <- function( object, values, select = c('first', 'last', 'common', 'all'), simplify = TRUE, ... ) { select <- select[1L] select <- match.arg(arg = select) values <- intersect(x = values, y = rownames(x = object)) p <- progressor(along = values) obs <- sapply( X = values, FUN = function(x) { vals <- colnames(x = object)[which(x = object[x, , drop = TRUE])] p() return(vals) }, simplify = FALSE, USE.NAMES = TRUE ) obs <- Filter(f = length, x = obs) obs <- switch( EXPR = select, 'first' = lapply(X = obs, FUN = '[[', 1L), 'last' = lapply( X = obs, FUN = function(x) { return(x[[length(x = x)]]) } ), common = { counts <- table(unlist(x = obs)) tmp <- obs obs <- vector(mode = 'character', length = length(x = tmp)) names(x = obs) <- names(x = tmp) for (i in seq_along(along.with = obs)) { obs[i] <- names(x = which.max( x = counts[names(x = counts) %in% tmp[[i]]] )) } obs }, obs ) if (isTRUE(x = simplify)) { tmp <- obs obs <- unlist(x = tmp) names(x = obs) <- make.unique(names = rep.int( x = names(x = tmp), times = vapply(X = tmp, FUN = length, FUN.VALUE = numeric(length = 1L)) )) } return(obs) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Internal #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # S4 methods #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' Matrix-like Subsetting for \link[=LogMap]{Logical Maps} #' #' @inheritParams base::`[` #' @inheritParams LogMap-class #' @param i,j Vectors of values (\code{i}) and observations (\code{j}) to pull #' from \code{x} #' @template param-dots-method #' #' @note \code{i} is not reordable; passing a different order for \code{i} #' will return a subset with rows in the same order as \code{x} #' #' @name [,LogMap #' @rdname sub-LogMap-method #' #' @keywords internal #' #' @examples #' map <- LogMap(letters[1:10]) #' map[['obs']] <- c(1, 3, 7) #' map[['entry']] <- c(2, 7, 10) #' #' map[] #' map[1:5, 2L] #' map[c("b", "c", "f"), "obs"] #' #' # Pass `drop = TRUE` to cast to `matrix` #' map[1:3, , drop = TRUE] #' #' # Note that `i` is non-reordable #' rownames(map)[1:3] #' map[c("b", "c", "a"), , drop = TRUE] #' NULL #' @rdname sub-LogMap-method #' setMethod( f = '[', signature = c(x = 'LogMap', i = 'missing', j = 'missing'), definition = function(x, i, j, ..., drop = FALSE) { return(x) } ) #' @rdname sub-LogMap-method #' setMethod( f = '[', signature = c(x = 'LogMap', i = 'character', j = 'character'), definition = function(x, i, j, ..., drop = FALSE) { i <- i[MatchCells(new = i, orig = rownames(x = x), ordered = TRUE)] x <- as.matrix(x = x)[i, j, drop = drop] if (!isTRUE(x = drop)) { x <- as(object = x, Class = 'LogMap') } return(x) } ) #' @rdname sub-LogMap-method #' setMethod( f = '[', signature = c(x = 'LogMap', i = 'character', j = 'missing'), definition = function(x, i, j, ..., drop = FALSE) { i <- i[MatchCells(new = i, orig = rownames(x = x), ordered = TRUE)] x <- as.matrix(x = x)[i, , drop = drop] if (!isTRUE(x = drop)) { x <- as(object = x, Class = 'LogMap') } return(x) } ) #' @rdname sub-LogMap-method #' setMethod( f = '[', signature = c(x = 'LogMap', i = 'missing', j = 'character'), definition = function(x, i, j, ..., drop = FALSE) { x <- as.matrix(x = x)[, j, drop = drop] if (!isTRUE(x = drop)) { x <- as(object = x, Class = 'LogMap') } return(x) } ) #' @rdname sub-LogMap-method #' setMethod( f = '[', signature = c(x = 'LogMap', i = 'numeric', j = 'missing'), definition = function(x, i, j, ..., drop = FALSE) { stopifnot(is_bare_integerish(x = i)) if (is.unsorted(x = i)) { i <- sort(x = i) } i <- rownames(x = x)[i] return(callNextMethod(x, i, ..., drop = drop)) } ) #' @rdname sub-LogMap-method #' setMethod( f = '[', signature = c(x = 'LogMap', i = 'missing', j = 'numeric'), definition = function(x, i, j, ..., drop = FALSE) { stopifnot(is_bare_integerish(x = j)) j <- colnames(x = x)[j] return(callNextMethod(x, , j, ..., drop = drop)) } ) #' @rdname sub-LogMap-method #' setMethod( f = '[', signature = c(x = 'LogMap', i = 'numeric', j = 'numeric'), definition = function(x, i, j, ..., drop = FALSE) { stopifnot(is_bare_integerish(x = i), is_bare_integerish(x = j)) if (is.unsorted(x = i)) { i <- sort(x = i) } i <- rownames(x = x)[i] j <- colnames(x = x)[j] return(callNextMethod(x, i, j, ..., drop = drop)) } ) #' @rdname LogMap-class #' #' @param x A \code{LogMap} object #' @param i A character vector of length 1, or \code{NULL} #' @param j Not used #' @param ... Ignored #' #' @return \code{[[}: if \code{i} is a character vector, the rownames that are #' mapped to \code{i}; otherwise the rownames of \code{x} #' #' @export #' #' @order 2 #' setMethod( f = '[[', signature = c(x = 'LogMap', i = 'character', j = 'missing'), definition = function(x, i, ...) { i <- i[1] i <- match.arg(arg = i, choices = colnames(x = x)) return(rownames(x = x)[x[, i, drop = TRUE]]) } ) #' \code{\link{LogMap}} Interaction Methods #' #' Additional methods for using \code{[[} with \code{\link{LogMap}} objects #' #' @inheritParams LogMap #' @param i An integer or numeric vector of length 1 #' #' @return The rownames that are mapped to \code{i} #' #' @rdname sub-sub-LogMap-internal-method #' #' @keywords internal #' setMethod( f = '[[', signature = c(x = 'LogMap', i = 'integer', j = 'missing'), definition = function(x, i, ...) { return(x[[colnames(x = x)[i]]]) } ) #' @rdname LogMap-class #' #' @export #' #' @order 3 #' setMethod( f = '[[', signature = c(x = 'LogMap', i = 'missing', j = 'missing'), definition = function(x, ...) { return(slot(object = x, name = '.Data')) } ) #' @rdname sub-sub-LogMap-internal-method #' setMethod( f = '[[', signature = c(x = 'LogMap', i = 'numeric', j = 'missing'), definition = function(x, i, ...) { return(x[[as.integer(x = i)]]) } ) #' @rdname LogMap-class #' #' @export #' #' @order 4 #' setMethod( f = '[[', signature = c(x = 'LogMap', i = 'NULL', j = 'missing'), definition = function(x, i, ...) { return(rownames(x = x)) } ) #' @rdname LogMap-class #' #' @param value A character or integer vector of values to record in the map #' for \code{i}, or \code{NULL} to remove the record for \code{i} #' #' @return \code{[[<-}: If \code{value} is \code{NULL}, then \code{x} without #' the observations for \code{i}; otherwise, \code{x} with a new column for #' \code{i} recording a \code{TRUE} for all values present in \code{value} #' #' @export #' #' @order 5 #' setMethod( f = '[[<-', signature = c( x = 'LogMap', i = 'character', j = 'missing', value = 'character' ), definition = function(x, i, ..., value) { value <- MatchCells(new = rownames(x = x), orig = value) x[[i]] <- value return(x) } ) #' @rdname LogMap-class #' #' @export #' #' @order 6 #' setMethod( f = '[[<-', signature = c( x = 'LogMap', i = 'character', j = 'missing', value = 'integer' ), definition = function(x, i, ..., value) { if (i %in% colnames(x = x)) { x[[i]] <- NULL } value <- MatchCells(new = value, rownames(x = x)) mat <- slot(object = x, name = '.Data') if (length(x = value)) { mat <- cbind( mat, matrix(data = FALSE, nrow = nrow(x = x), dimnames = list(NULL, i)) ) mat[value, i] <- TRUE } slot(object = x, name = '.Data') <- mat validObject(object = x) return(x) } ) #' @rdname LogMap-class #' #' @export #' #' @order 7 #' setMethod( f = '[[<-', signature = c(x = 'LogMap', i = 'character', j = 'missing', value = 'NULL'), definition = function(x, i, ..., value) { mat <- slot(object = x, name = '.Data') for (name in i) { idx <- which(x = colnames(x = mat) == name) if (length(x = idx)) { mat <- mat[, -idx, drop = FALSE] } } slot(object = x, name = '.Data') <- mat validObject(object = x) return(x) } ) #' @rdname LogMap-class #' #' @export #' #' @order 8 #' setMethod( f = '[[<-', signature = c( x = 'LogMap', i = 'character', j = 'missing', value = 'numeric' ), definition = function(x, i, ..., value) { value <- as.integer(x = value) x[[i]] <- value return(x) } ) #' \code{\link{LogMap}} Object Overview #' #' Overview of a \code{\link{LogMap}} object #' #' @param object A \code{\link{LogMap}} object #' #' @template return-show #' #' @concept logmap #' setMethod( f = 'show', signature = 'LogMap', definition = function(object) { cat( "A logical map for", nrow(x = object), "values across", ncol(x = object), "observations" ) return(invisible(x = NULL)) } ) #' Logical Map Validity #' #' @templateVar cls LogMap #' @template desc-validity #' #' @section Data Validation: #' Logical maps must be a logical matrix containing only TRUE or FALSE values #' #' @section Value Validation: #' All values must be named within the rownames of the object. Duplicate or #' empty (\code{""}) values are not allowed #' #' @section Observation Validation: #' All observations must be named within the column names of the object. #' Duplicate or empty (\code{""}) observations are not allowed #' #' @name LogMap-validity #' #' @family logmap #' @seealso \code{\link[methods]{validObject}} #' #' @examples #' map <- LogMap(letters[1:10]) #' map[['obs']] <- c(1, 3, 7) #' map[['entry']] <- c(2, 7, 10) #' validObject(map) #' setValidity( Class = 'LogMap', method = function(object) { if (isFALSE(x = getOption(x = "Seurat.object.validate", default = TRUE))) { warn( message = paste("Not validating", class(x = object)[1L], "objects"), class = 'validationWarning' ) return(TRUE) } valid <- NULL # Ensure we have a logical matrix if (!is.logical(x = object)) { valid <- c(valid, "The map must be a logical matrix") } if (any(is.na(x = object))) { valid <- c(valid, "The may may not contain NAs") } # Check rownames if (is.null(x = rownames(x = object))) { valid <- c(valid, "Rownames must be supplied") } if (any(!nzchar(x = rownames(x = object)))) { valid <- c(valid, "Rownames cannot be empty strings") } if (anyDuplicated(x = rownames(x = object))) { valid <- c(valid, "Duplicate rownames not allowed") } # Check colnames if (!is.null(x = colnames(x = object))) { if (any(!nzchar(x = colnames(x = object)))) { valid <- c(valid, "Columnn names cannot be empty strings") } if (anyDuplicated(x = colnames(x = object))) { valid <- c(valid, "Duplicate colnames not allowed") } } else if (ncol(x = object)) { valid <- c(valid, "Colnames must be supplied") } return(valid %||% TRUE) } ) SeuratObject/R/graph.R0000644000176200001440000001356014520004144014270 0ustar liggesusers#' @include zzz.R #' @include generics.R #' NULL #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Class definitions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' The Graph Class #' #' The Graph class inherits from \code{\link[Matrix:sparseMatrix]{dgCMatrix}}. #' We do this to enable future expandability of graphs. #' #' @slot assay.used Optional name of assay used to generate \code{Graph} object #' #' @name Graph-class #' @rdname Graph-class #' #' @exportClass Graph #' #' @seealso \code{\link[Matrix]{dgCMatrix-class}} #' #' @family graph #' Graph <- setClass( Class = 'Graph', contains = "dgCMatrix", slots = list( assay.used = 'character' ) ) #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Functions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for Seurat-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' @importFrom methods as #' #' @rdname as.Graph #' @export #' @method as.Graph Matrix #' #' @examples #' # converting sparse matrix #' mat <- Matrix::rsparsematrix(nrow = 10, ncol = 10, density = 0.1) #' rownames(x = mat) <- paste0("feature_", 1:10) #' colnames(x = mat) <- paste0("cell_", 1:10) #' g <- as.Graph(x = mat) #' as.Graph.Matrix <- function(x, ...) { CheckDots(...) x <- as.sparse(x = x) if (is.null(x = rownames(x = x))) { abort(message = "Please provide rownames to the matrix before converting to a Graph") } if (is.null(x = colnames(x = x))) { abort(message = "Please provide colnames to the matrix before converting to a Graph") } return(as(object = x, Class = "Graph")) } #' @rdname as.Graph #' @export #' @method as.Graph matrix #' #' @examples #' # converting dense matrix #' mat <- matrix(data = 1:16, nrow = 4) #' rownames(x = mat) <- paste0("feature_", 1:4) #' colnames(x = mat) <- paste0("cell_", 1:4) #' g <- as.Graph(x = mat) #' as.Graph.matrix <- as.Graph.Matrix #' @param weighted If TRUE, fill entries in Graph matrix with value from the #' nn.dist slot of the Neighbor object #' #' @rdname as.Graph #' @export #' @method as.Graph Neighbor #' as.Graph.Neighbor <- function(x, weighted = TRUE, ...) { CheckDots(...) j <- as.integer(x = Indices(object = x) - 1) i <- as.integer(x = rep(x = (1:nrow(x = x)) - 1, times = ncol(x = x))) vals <- if (weighted) { as.vector(x = Distances(object = x)) } else { 1 } graph <- new( Class = "dgTMatrix", i = i, j = j, x = vals, Dim = as.integer(x = c(nrow(x = x), nrow(x = x))) ) colnames(x = graph) <- rownames(x = graph) <- Cells(x = x) graph <- as.Graph.Matrix(x = graph) return(graph) } #' @method Cells Graph #' @export #' Cells.Graph <- function(x, margin = 1L, ...) { margin <- as.integer(x = margin) if (is_na(x = margin)) { return(Reduce(f = union, x = dimnames(x = x))) } if (!isTRUE(margin %in% c(1L, 2L))) { stop("'margin' must be either 1 or 2", call. = FALSE) } return(dimnames(x = x)[[margin]]) } #' @rdname DefaultAssay #' @export #' @method DefaultAssay Graph #' DefaultAssay.Graph <- function(object, ...) { # object <- UpdateSlots(object = object) assay <- slot(object = object, name = 'assay.used') if (!length(x = assay)) { assay <- NULL } return(assay) } #' @rdname DefaultAssay #' @export #' @method DefaultAssay<- Graph #' "DefaultAssay<-.Graph" <- function(object, ..., value) { op <- options(Seurat.object.validate = FALSE) on.exit(expr = options(op)) object <- suppressWarnings(expr = UpdateSlots(object = object)) if (!length(x = value) || !isTRUE(x = nzchar(x = value))) { value <- character(length = 0L) } slot(object = object, name = 'assay.used') <- value options(op) validObject(object = object) return(object) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for R-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # S4 methods #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% setValidity( Class = 'Graph', method = function(object) { if (.GetSeuratCompat() < '5.0.0') { return(TRUE) } if (isFALSE(x = getOption(x = "Seurat.object.validate", default = TRUE))) { warn( message = paste("Not validating", class(x = object)[1L], "objects"), class = 'validationWarning' ) return(TRUE) } valid <- NULL # Check dimnames dnames <- dimnames(x = object) for (i in seq_along(along.with = dnames)) { type <- c('row', 'column')[i] if (is.null(x = dnames[[i]])) { valid <- c(valid, paste(type, "names must be provided")) } else if (any(!nzchar(x = dnames[[i]]))) { valid <- c(valid, paste(type, "names must not be empty strings")) } else if (anyDuplicated(x = dnames[[i]])) { valid <- c(valid, paste(type, "names may not contain duplicates")) } } # Check default assay assay <- DefaultAssay(object = object) if (length(x = assay) && !nzchar(x = assay)) { valid <- c(valid, "'assay.used' may not be an empty character ('')") } return(valid %||% TRUE) } ) #' Graph Object Overview #' #' Overview of a \code{\link{Graph}} Object #' #' @template return-show #' #' @keywords internal #' #' @concept graph #' #' @examples #' pbmc_small[["RNA_snn"]] #' setMethod( f = 'show', signature = 'Graph', definition = function(object) { cat( "A Graph object containing", nrow(x = object), "cells" ) } ) #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Internal #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% SeuratObject/R/keymixin.R0000644000176200001440000001674214520004144015031 0ustar liggesusers#' @include zzz.R #' @include generics.R #' NULL #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Class definitions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' A Mixin for Keyed objects #' #' A mixin (virtual class) for enabling keyed objects; provides consistent #' behavior for getting, setting, and validating keys #' #' @template slot-key #' #' @keywords internal #' #' @exportClass KeyMixin #' #' @aliases KeyMixin #' #' @family key #' setClass( Class = 'KeyMixin', contains = 'VIRTUAL', slots = list(key = 'character') ) #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Functions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' Regex Pattern for Keys #' #' @return Returns the regex pattern for keys #' (\dQuote{\Sexpr[stage=build]{SeuratObject:::.KeyPattern()}}) #' #' @keywords internal #' #' @export #' #' @family key #' .KeyPattern <- function() { return('^[a-zA-Z][a-zA-Z0-9]*_$') } #' Generate a Random Key #' #' @inheritParams RandomName #' #' @return Returns a valid key #' #' @keywords internal #' #' @export #' #' @family key #' #' @examples #' set.seed(42L) #' .RandomKey() #' .RandomKey <- function(length = 7L, ...) { return(Key( object = RandomName( length = length, chars = c(letters, LETTERS, seq.int(from = 0L, to = 9L)), ... ), quiet = TRUE )) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for Seurat-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' @param object An object #' @param quiet Suppress warnings when updating characters to keys #' @param ... Ignored #' @param value A key to set #' #' @details \code{Key.character}: Update a character to a key #' #' @return \code{Key.character}: \code{object} but as a syntactically-valid key #' #' @rdname KeyMixin-class #' @method Key character #' @export #' Key.character <- function(object, quiet = FALSE, ...) { f <- ifelse(test = isTRUE(x = quiet), yes = suppressWarnings, no = identity) return(f(UpdateKey(key = object))) } #' @details \code{Key.KeyMixin}: Get the key of a keyed object #' #' @return \code{Key.KeyMixin}: The key from \code{object}; if no key set, #' returns \code{NULL} #' #' @rdname KeyMixin-class #' @method Key KeyMixin #' @export #' Key.KeyMixin <- function(object, ...) { key <- slot(object = object, name = 'key') if (!length(x = key)) { key <- NULL } return(key) } #' @details \code{Key<-}: Set the key of a keyed object #' #' @return \code{Key<-}: \code{object} with the key set to \code{value} #' #' @rdname KeyMixin-class #' @method Key<- KeyMixin #' @export #' "Key<-.KeyMixin" <- function(object, ..., value) { slot(object = object, name = 'key') <- Key(object = value, ...) validObject(object = object) return(object) } #' @method Key NULL #' @export #' Key.NULL <- function(object, ...) { return(NULL) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for R-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Internal #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' Internal Key Methods #' #' Internal key methods for classes that inherit from \code{\link{KeyMixin}}; #' these functions are designed to be used as the body for methods for #' \code{Key()} and \code{Key<-()} when an immediate public method is required. #' Generally speaking, classes that inherit from \code{KeyMixin} should use the #' \code{KeyMixin} methods for \code{Key()} and \code{Key<-()} #' #' @inheritParams Key #' #' @inherit Key return #' #' @keywords internal #' #' @noRd #' .Key <- function(object, ...) { CheckDots(...) return(NextMethod()) } #' @rdname dot-Key #' #' @noRd #' ".Key<-" <- function(object, ..., value) { CheckDots(...) object <- UpdateSlots(object = object) object <- NextMethod() return(object) } #' Update a Key #' #' @param key A character to become a Seurat Key #' #' @return An updated Key that's valid for Seurat #' #' @keywords internal #' #' @family key #' #' @noRd #' UpdateKey <- function(key) { key.msg <- 'Keys should be one or more alphanumeric characters followed by an underscore' if (isTRUE(x = grepl(pattern = .KeyPattern(), x = key))) { return(key) } new.key <- regmatches( x = key, m = gregexpr(pattern = '[[:alnum:]]+', text = key) ) new.key <- paste0(paste(unlist(x = new.key), collapse = ''), '_') if (new.key == '_') { new.key <- paste0(RandomName(length = 3), '_') } warning( key.msg, ", setting key from ", key, " to ", new.key, call. = FALSE, immediate. = TRUE ) return(new.key) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # S4 methods #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' Key Validity #' #' Validation of \code{\link{KeyMixin}} objects is handled by #' \code{\link[methods]{validObject}} #' #' @section Key Validation: #' Keys must be a one-length character vector; a key must be composed of one #' of the following: #' \itemize{ #' \item An empty string (eg. \dQuote{\code{''}}) where \code{nzchar() == 0} #' \item An string composed of one or more alphanumeric values #' (both lower- and upper-case) that ends with an underscore #' (\dQuote{\code{_}}); the first character must be a letter #' } #' Keys that are not empty strings are validated with the regex #' \dQuote{\code{\Sexpr[stage=build]{SeuratObject:::.KeyPattern()}}} #' #' @importFrom rlang is_scalar_character #' #' @keywords internal #' #' @name Key-validity #' #' @family key #' setValidity( Class = 'KeyMixin', method = function(object) { if (isFALSE(x = getOption(x = "Seurat.object.validate", default = TRUE))) { warn( message = paste("Not validating", class(x = object)[1L], "objects"), class = 'validationWarning' ) return(TRUE) } valid <- NULL key <- Key(object = object) # Ensure key has length of 1 if (!is.null(x = key) && .GetSeuratCompat() >= '5.0.0') { if (!is_scalar_character(x = key)) { valid <- c(valid, "Keys must be a one-length character vector") } else if (is_na(x = key)) { valid <- c(valid, "Keys may not be 'NA'") } else if (nzchar(x = key) && !grepl(pattern = .KeyPattern(), x = key)) { # Ensure proper key composition valid <- c( valid, paste0("Keys must match the pattern '", .KeyPattern(), "'") ) } } return(valid %||% TRUE) } ) .CheckKey <- function(key, existing = NULL, name = NULL) { if (rlang::is_missing(x = key) || !length(x = key) || !nzchar(x = key)) { key <- Key(object = tolower(name) %||% RandomName(), quiet = TRUE) } if (!is.null(x = names(x = existing)) && !is.null(x = name)) { existing <- existing[setdiff(x = names(x = existing), y = name)] } if (key %in% existing) { old <- key key <- Key(object = tolower(x = name %||% RandomName()), quiet = TRUE) i <- 1L n <- 5L while (key %in% existing) { key <- Key(object = RandomName(length = n), quiet = TRUE) i <- i + 1L if (!i %% 7L) { n <- n + 2L } } warn( message = paste( "Key", sQuote(x = old), "taken, using", sQuote(x = key), "instead" ) ) } return(key) } SeuratObject/R/assay.R0000644000176200001440000015023314523024456014321 0ustar liggesusers#' @include zzz.R #' @include generics.R #' @include default.R #' @include graph.R #' @include keymixin.R #' NULL #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Class definitions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% setClassUnion(name = 'AnyMatrix', members = c("matrix", "dgCMatrix")) #' The Assay Class #' #' The Assay object is the basic unit of Seurat; each Assay stores raw, #' normalized, and scaled data as well as cluster information, variable #' features, and any other assay-specific metadata. Assays should contain single #' cell expression data such as RNA-seq, protein, or imputed expression data. #' #' @slot counts Unnormalized data such as raw counts or TPMs #' @slot data Normalized expression data #' @slot scale.data Scaled expression data # @slot key Key for the Assay #' @slot assay.orig Original assay that this assay is based off of. Used to #' track assay provenance #' @slot var.features Vector of features exhibiting high variance across #' single cells #' @slot meta.features Feature-level metadata # @slot misc Utility slot for storing additional data associated with the assay #' @template slot-misc #' @template slot-key #' #' @name Assay-class #' @rdname Assay-class #' @exportClass Assay #' #' @family assay #' #' @aliases Assay #' setClass( Class = 'Assay', contains = 'KeyMixin', slots = c( counts = 'AnyMatrix', data = 'AnyMatrix', scale.data = 'matrix', # key = 'character', assay.orig = 'OptionalCharacter', var.features = 'vector', meta.features = 'data.frame', misc = 'OptionalList' ) ) #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Functions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' Create an Assay object #' #' Create an Assay object from a feature (e.g. gene) expression matrix. The #' expected format of the input matrix is features x cells. #' #' Non-unique cell or feature names are not allowed. Please make unique before #' calling this function. #' #' @param counts Unnormalized data such as raw counts or TPMs #' @param data Prenormalized data; if provided, do not pass \code{counts} #' @param min.cells Include features detected in at least this many cells. Will #' subset the counts matrix as well. To reintroduce excluded features, create a #' new object with a lower cutoff #' @param min.features Include cells where at least this many features are #' detected #' @param key Optional key to initialize assay with #' @param check.matrix Check counts matrix for NA, NaN, Inf, and #' non-integer values #' @param ... Arguments passed to \code{\link{as.sparse}} #' #' @return A \code{\link{Assay}} object #' #' @importFrom methods as #' @importFrom Matrix colSums rowSums #' #' @export #' #' @family assay #' #' @examples #' \dontrun{ #' pbmc_raw <- read.table( #' file = system.file('extdata', 'pbmc_raw.txt', package = 'Seurat'), #' as.is = TRUE #' ) #' pbmc_rna <- CreateAssayObject(counts = pbmc_raw) #' pbmc_rna #' } #' CreateAssayObject <- function( counts, data, min.cells = 0, min.features = 0, key = NULL, check.matrix = FALSE, ... ) { if (missing(x = counts) && missing(x = data)) { abort(message = "Must provide either 'counts' or 'data'") } else if (!missing(x = counts) && !missing(x = data)) { abort(message = "Either 'counts' or 'data' must be missing; both cannot be provided") } else if (!missing(x = counts)) { # check that dimnames of input counts are unique if (anyDuplicated(x = rownames(x = counts))) { warn( message = "Non-unique features (rownames) present in the input matrix, making unique" ) rownames(x = counts) <- make.unique(names = rownames(x = counts)) } if (anyDuplicated(x = colnames(x = counts))) { warn( message = "Non-unique cell names (colnames) present in the input matrix, making unique" ) colnames(x = counts) <- make.unique(names = colnames(x = counts)) } if (is.null(x = colnames(x = counts))) { abort(message = "No cell names (colnames) names present in the input matrix") } if (any(rownames(x = counts) == '')) { abort(message = "Feature names of counts matrix cannot be empty") } if (nrow(x = counts) > 0 && is.null(x = rownames(x = counts))) { abort(message = "No feature names (rownames) names present in the input matrix") } if (!inherits(x = counts, what = 'dgCMatrix')) { if (inherits(x = counts, what = "data.frame")) { counts <- as.sparse(x = counts, ...) } else { counts <- as.sparse(x = counts) } } if (isTRUE(x = check.matrix)) { CheckMatrix(object = counts) } # Filter based on min.features if (min.features > 0) { nfeatures <- Matrix::colSums(x = counts > 0) counts <- counts[, which(x = nfeatures >= min.features)] } # filter genes on the number of cells expressing if (min.cells > 0) { num.cells <- Matrix::rowSums(x = counts > 0) counts <- counts[which(x = num.cells >= min.cells), ] } data <- counts } else if (!missing(x = data)) { # check that dimnames of input data are unique if (anyDuplicated(x = rownames(x = data))) { warn( message = "Non-unique features (rownames) present in the input matrix, making unique" ) rownames(x = data) <- make.unique(names = rownames(x = data)) } if (anyDuplicated(x = colnames(x = data))) { warn( message = "Non-unique cell names (colnames) present in the input matrix, making unique" ) colnames(x = data) <- make.unique(names = colnames(x = data)) } if (is.null(x = colnames(x = data))) { abort(message = "No cell names (colnames) names present in the input matrix") } if (any(rownames(x = data) == '')) { abort(message = "Feature names of data matrix cannot be empty", call. = FALSE) } if (nrow(x = data) > 0 && is.null(x = rownames(x = data))) { abort(message = "No feature names (rownames) names present in the input matrix") } if (min.cells != 0 | min.features != 0) { warn( message = "No filtering performed if passing to data rather than counts" ) } counts <- new(Class = 'matrix') } # Ensure row- and column-names are vectors, not arrays if (!is.vector(x = rownames(x = counts))) { rownames(x = counts) <- as.vector(x = rownames(x = counts)) } if (!is.vector(x = colnames(x = counts))) { colnames(x = counts) <- as.vector(x = colnames(x = counts)) } if (!is.vector(x = rownames(x = data))) { rownames(x = data) <- as.vector(x = rownames(x = data)) } if (!is.vector(x = colnames(x = data))) { colnames(x = data) <- as.vector(x = colnames(x = data)) } counts <- CheckFeaturesNames(data = counts) data <- CheckFeaturesNames(data = data) # Initialize meta.features init.meta.features <- data.frame(row.names = rownames(x = data)) misc <- if (.GetSeuratCompat() < '5.0.0') { list() } else { calcN_option <- getOption( x = 'Seurat.object.assay.calcn', default = Seurat.options$Seurat.object.assay.calcn ) list(calcN = calcN_option %||% TRUE) } assay <- new( Class = 'Assay', counts = counts, data = data, scale.data = new(Class = 'matrix'), key = Key(object = key)[1L] %||% '', meta.features = init.meta.features, misc = misc ) return(assay) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for Seurat-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' @importFrom Matrix colSums #' #' @method .CalcN Assay #' @export #' .CalcN.Assay <- function(object, layer = 'counts', ...) { layer <- tryCatch( expr = Layers(object = object, search = layer), error = function(...) NULL ) if (is.null(x = layer)) { return(NULL) } ldat <- LayerData(object = object, layer = layer) if (IsMatrixEmpty(x = ldat) || !inherits(x = ldat, what = 'Matrix')) { return(NULL) } cells_stat <- .CalcN.default(object = ldat) return(cells_stat) } #' @rdname AddMetaData #' # @templateVar fname AddMetaData # @templateVar version 4 # @template name-oldv #' #' @export #' @method AddMetaData Assay #' AddMetaData.Assay <- function(object, metadata, col.name = NULL) { if (is.null(x = col.name) && (is.atomic(x = metadata) && !is.matrix(x = metadata))) { abort(message = "'col.name' must be provided for atomic meta data") } if (inherits(x = metadata, what = c('matrix', 'Matrix'))) { metadata <- as.data.frame(x = metadata) } col.name <- col.name %||% names(x = metadata) %||% colnames(x = metadata) if (is.null(x = col.name)) { abort(message = "No metadata name provided and could not infer it from metadata object") } object[[col.name]] <- metadata return(object) } #' @rdname DefaultAssay #' @export #' @method DefaultAssay Assay #' DefaultAssay.Assay <- function(object, ...) { object <- UpdateSlots(object = object) return(slot(object = object, name = 'assay.orig')) } #' @rdname DefaultAssay #' @export #' @method DefaultAssay<- Assay #' "DefaultAssay<-.Assay" <- function(object, ..., value) { object <- UpdateSlots(object = object) slot(object = object, name = 'assay.orig') <- value return(object) } #' @rdname DefaultLayer #' @method DefaultLayer Assay #' @export #' DefaultLayer.Assay <- function(object, ...) { return('data') } #' @method Features Assay #' @export #' Features.Assay <- function( x, layer = c('data', 'scale.data', 'counts'), slot = deprecated(), ... ) { if (is_present(arg = slot)) { .Deprecate( when = '5.0.0', what = 'Features(slot = )', with = 'Features(layer = )' ) layer <- slot } layer <- layer[1L] %||% 'data' layer <- match.arg(arg = layer) features <- rownames(x = GetAssayData(object = x, layer = layer)) if (!length(x = features)) { features <- NULL } return(features) } #' @method FetchData Assay #' @export #' FetchData.Assay <- function( object, vars, cells = NULL, layer = NULL, slot = deprecated(), ... ) { if (is_present(arg = slot)) { .Deprecate( when = '5.0.0', what = 'FetchData(slot = )', with = 'FetchData(layer = )' ) layer <- layer %||% slot } # Identify slot to use layer <- layer %||% 'data' layer <- match.arg(arg = layer, choices = c('counts', 'data', 'scale.data')) # Identify cells to use cells <- cells %||% colnames(x = object) if (is.numeric(x = cells)) { cells <- colnames(x = object)[cells] } cells.orig <- cells cells <- intersect(x = cells, y = colnames(x = object)) if (length(x = cells) != length(x = cells.orig)) { warn(message = paste( "Removing", length(x = cells.orig) - length(x = cells), "cells not present in the assay" )) } # Check vars orig <- vars vars <- gsub( pattern = paste0('^', Key(object = object)), replacement = '', x = vars ) # Pull expression information mat <- GetAssayData(object = object, layer = layer) if (IsMatrixEmpty(x = mat)) { abort(message = paste("Layer", sQuote(x = layer), "is empty in this assay")) } vars <- intersect(x = vars, y = rownames(x = mat)) tf <- .GetMethod(fxn = 't', cls = class(x = mat)) data.fetched <- as.data.frame(x = as.matrix( x = tf(x = mat[vars, cells, drop = FALSE]) )) # Add keys to keyed vars keyed.features <- paste0(Key(object = object), names(x = data.fetched)) keyed.idx <- which(x = keyed.features %in% orig) if (length(x = keyed.idx)) { names(x = data.fetched)[keyed.idx] <- keyed.features[keyed.idx] } # Check the final list of features missing <- setdiff(x = orig, y = names(x = data.fetched)) if (length(x = missing) == length(x = orig)) { abort(message = "None of the requested features found") } else if (length(x = missing)) { warn(message = paste( "The following features could not be found", paste(missing, collapse = ', ') )) } return(data.fetched) } #' @rdname AssayData #' @export #' @method GetAssayData Assay #' #' @examples #' # Get the data directly from an Assay object #' GetAssayData(pbmc_small[["RNA"]], layer = "data")[1:5,1:5] #' GetAssayData.Assay <- function( object, layer = c('data', 'scale.data', 'counts'), slot = deprecated(), ... ) { CheckDots(...) if (is_present(arg = slot)) { .Deprecate( when = '5.0.0', what = 'GetAssayData(slot = )', with = 'GetAssayData(layer = )' ) layer <- slot } layer <- layer[1L] %||% 'data' layer <- match.arg(arg = layer) return(methods::slot(object = object, name = layer)) } #' @rdname VariableFeatures #' @export #' @method HVFInfo Assay #' #' @examples #' # Get the HVF info directly from an Assay object #' HVFInfo(pbmc_small[["RNA"]], method = 'vst')[1:5, ] #' HVFInfo.Assay <- function( object, method, status = FALSE, selection.method = deprecated(), ... ) { CheckDots(...) if (is_present(arg = selection.method)) { .Deprecate( when = '5.0.0', what = 'HVFInfo(selection.method = )', with = 'HVFInfo(method = )' ) method <- selection.method } disp.methods <- c('mean.var.plot', 'dispersion', 'disp') if (tolower(x = method) %in% disp.methods) { method <- 'mvp' } method <- switch( EXPR = tolower(x = method), sctransform = 'sct', method ) vars <- switch( EXPR = method, vst = c('mean', 'variance', 'variance.standardized'), mvp = c('mean', 'dispersion', 'dispersion.scaled'), sct = c('gmean', 'variance', 'residual_variance'), abort(message = paste("Unknown method:", sQuote(x = method))) ) tryCatch( expr = hvf.info <- object[[paste(method, vars, sep = '.')]], error = function(e) { stop( "Unable to find highly variable feature information for method '", method, "'", call. = FALSE ) } ) colnames(x = hvf.info) <- vars if (status) { hvf.info$variable <- object[[paste0(method, '.variable')]] } return(hvf.info) } #' @rdname Key #' @export #' @method Key Assay #' #' @examples #' # Get an Assay key #' Key(pbmc_small[["RNA"]]) #' Key.Assay <- function(object, ...) { CheckDots(...) return(slot(object = object, name = 'key')) } #' @rdname Key #' @export #' @method Key<- Assay #' #' @examples #' # Set the key for an Assay #' Key(pbmc_small[["RNA"]]) <- "newkey_" #' Key(pbmc_small[["RNA"]]) #' "Key<-.Assay" <- function(object, ..., value) { CheckDots(...) slot(object = object, name = 'key') <- value return(object) } #' @rdname Layers #' @method LayerData Assay #' @export #' LayerData.Assay <- function( object, layer = NULL, cells = NULL, features = NULL, slot = deprecated(), ... ) { if (is_present(arg = slot)) { deprecate_stop( when = "5.0.0", what = "LayerData(slot = )", with = "LayerData(layer = )" ) } # Figure out which matrix we're pulling layer <- layer[1L] %||% "data" # layer <- match.arg( # arg = layer, # choices = Layers(object = object, search = FALSE) # ) # Handle empty layers if (IsMatrixEmpty(x = methods::slot(object = object, name = layer))) { msg <- paste("Layer", sQuote(x = layer), "is empty") opt <- getOption( x = 'Seurat.object.assay.v3.missing_layer', default = Seurat.options$Seurat.object.assay.v3.missing_layer ) opt <- tryCatch( expr = arg_match0(arg = opt, values = c('matrix', 'null', 'error')), error = function(...) { return(Seurat.options$Seurat.object.assay.v3.missing_layer) } ) if (opt == 'error') { abort(message = msg) } warn(message = msg) return(switch( EXPR = opt, matrix = switch( EXPR = layer, scale.data = new(Class = 'matrix'), new(Class = 'dgCMatrix') ), NULL )) } # Allow cell/feature subsets cells <- cells %||% colnames(x = object) features <- features %||% Features(x = object, layer = layer) if (is_bare_integerish(x = cells, finite = TRUE)) { cells <- colnames(x = object)[cells] } cells <- arg_match( arg = cells, values = colnames(x = object), multiple = TRUE ) if (is_bare_integerish(x = features, finite = TRUE)) { features <- Features(x = object, layer = layer)[features] } features <- arg_match( arg = features, values = Features(x = object, layer = layer), multiple = TRUE ) if (length(x = features) == 0) { stop('features are not found') } # Pull the matrix for the cells/features requested return(methods::slot(object = object, name = layer)[features, cells]) } #' @rdname Layers #' @method LayerData<- Assay #' @export #' "LayerData<-.Assay" <- function(object, layer, ..., value) { # Check the layer name layer <- layer[1L] layer <- match.arg( arg = layer, choices = Layers(object = object, search = FALSE) ) # Allow short-hand switch if (rlang::is_scalar_character(x = value)) { value <- arg_match0(arg = value, values = Layers(object = object)) value <- LayerData(object = object, layer = value) } # Prepare an empty matrix if value is NULL value <- value %||% switch( EXPR = layer, scale.data = new(Class = 'matrix'), counts = new(Class = 'dgCMatrix'), data = { if (IsMatrixEmpty(x = suppressWarnings(expr = LayerData(object = object, layer = 'counts')))) { abort(message = "Cannot remove the data layer") } warn(message = "Resetting the data matrix to the raw counts") LayerData(object = object, layer = 'counts') } ) # Check the class of the matrix if (!inherits(x = value, what = c('matrix', 'dgCMatrix'))) { abort(message = paste( "'value' must be a 'matrix' or 'dgCMatrix' in v3 Assays, not a", sQuote(x = class(x = value)[1L]) )) } if (!IsMatrixEmpty(x = value)) { vnames <- dimnames(x = value) # Check presence of cell- and feature-names if (is.null(x = vnames)) { if (!all(dim(x = value) == dim(x = object))) { abort(message = "New data must have feature and cell names") } dimnames(x = value) <- dimnames(x = object) } else if (any(.IsNull(x = vnames)) || !all(unlist(x = lapply(X = vnames, FUN = nzchar)))) { abort(message = "New data must have feature and cell names") } # Remove underscores from feature names if (any(grepl(pattern = '_', x = rownames(x = value)))) { warn( message = "Feature names cannot have underscores ('_'), replacing with dashes ('-')" ) rownames(x = value) <- gsub( pattern = '_', replacement = '-', x = rownames(x = value) ) } # Check the the cells if (ncol(x = value) != ncol(x = object)) { abort(message = "The new data must have the same number of cells as the current data") } else if (!all(colnames(x = value) %in% colnames(x = object))) { abort(message = "The new data must have the same cells as the current data") } value <- value[, colnames(x = object), drop = FALSE] # Check the features if (!any(rownames(x = value) %in% rownames(x = object))) { abort(message = "None of the features provided are present in the existing data") } else if (!all(rownames(x = value) %in% rownames(x = object))) { warn(message = "Extra features present in the the new data compared to the existing data") } features <- intersect(x = rownames(x = object), y = rownames(x = value)) value <- value[features, , drop = FALSE] if (layer %in% c('counts', 'data') && nrow(x = value) != nrow(x = object)) { abort(message = "The new data must have the same number of features as the current data") } } slot(object = object, name = layer) <- value validObject(object = object) return(object) } #' @rdname Layers #' @method Layers Assay #' @export #' Layers.Assay <- function(object, search = NA, ...) { layers <- c('counts', 'data', 'scale.data') if (isFALSE(x = search)) { return(layers) } layers <- Filter( f = function(x) { return(!IsMatrixEmpty(x = slot(object = object, name = x))) }, x = layers ) if (!length(x = layers)) { abort(message = "All matrices are empty in this Assay") } if (is.null(x = search)) { return(DefaultLayer(object = object)) } if (!is_na(x = search)) { layers <- intersect(x = search, y = layers) if (length(x = layers) == 0) { return(NULL) } } return(layers) } #' @param slot Name of specific bit of meta data to pull #' #' @rdname Misc #' @export #' @method Misc Assay #' Misc.Assay <- .Misc #' @rdname Misc #' @export #' @method Misc<- Assay #' "Misc<-.Assay" <- `.Misc<-` #' @param new.names vector of new cell names #' #' @rdname RenameCells #' @export #' @method RenameCells Assay #' #' @examples #' # Rename cells in an Assay #' head(x = colnames(x = pbmc_small[["RNA"]])) #' renamed.assay <- RenameCells( #' pbmc_small[["RNA"]], #' new.names = paste0("A_", colnames(x = pbmc_small[["RNA"]])) #' ) #' head(x = colnames(x = renamed.assay)) #' RenameCells.Assay <- function(object, new.names = NULL, ...) { CheckDots(...) names(new.names) <- NULL for (data.slot in c("counts", "data", "scale.data")) { old.data <- GetAssayData(object = object, layer = data.slot) if (ncol(x = old.data) <= 1) { next } colnames(x = slot(object = object, name = data.slot)) <- new.names } return(object) } #' @importFrom stats na.omit #' #' @rdname AssayData #' @export #' @method SetAssayData Assay #' #' @examples #' # Set an Assay layer directly #' count.data <- GetAssayData(pbmc_small[["RNA"]], layer = "counts") #' count.data <- as.matrix(x = count.data + 1) #' new.assay <- SetAssayData(pbmc_small[["RNA"]], layer = "counts", new.data = count.data) #' SetAssayData.Assay <- function( object, layer = c('data', 'scale.data', 'counts'), new.data, slot = deprecated(), ... ) { if (is_present(arg = slot)) { .Deprecate( when = '5.0.0', what = 'SetAssayData(slot = )', with = 'SetAssayData(layer = )' ) layer <- slot } CheckDots(...) layer <- layer[1] layer <- match.arg(arg = layer) if (!IsMatrixEmpty(x = new.data)) { if (any(grepl(pattern = '_', x = rownames(x = new.data)))) { warning( "Feature names cannot have underscores ('_'), replacing with dashes ('-')", call. = FALSE, immediate. = TRUE ) rownames(x = new.data) <- gsub( pattern = '_', replacement = '-', x = rownames(x = new.data) ) } if (ncol(x = new.data) != ncol(x = object)) { stop( "The new data doesn't have the same number of cells as the current data", call. = FALSE ) } num.counts <- nrow(x = object) counts.names <- rownames(x = object) if (layer == 'scale.data' && nrow(x = new.data) > num.counts) { warning( "Adding more features than present in current data", call. = FALSE, immediate. = TRUE ) } else if (layer %in% c('counts', 'data') && nrow(x = new.data) != num.counts) { warning( "The new data doesn't have the same number of features as the current data", call. = FALSE, immediate. = TRUE ) } if (!all(rownames(x = new.data) %in% counts.names)) { warning( "Adding features not currently present in the object", call. = FALSE, immediate. = TRUE ) } new.features <- na.omit(object = match( x = counts.names, table = rownames(x = new.data) )) new.cells <- colnames(x = new.data) if (!all(new.cells %in% colnames(x = object))) { stop( "All cell names must match current cell names", call. = FALSE ) } new.data <- new.data[new.features, colnames(x = object), drop = FALSE] if (layer %in% c('counts', 'data') && !all(dim(x = new.data) == dim(x = object))) { stop( "Attempting to add a different number of cells and/or features", call. = FALSE ) } } if (!is.vector(x = rownames(x = new.data))) { rownames(x = new.data) <- as.vector(x = rownames(x = new.data)) } if (!is.vector(x = colnames(x = new.data))) { colnames(x = new.data) <- as.vector(x = colnames(x = new.data)) } slot(object = object, name = layer) <- new.data return(object) } #' @param decreasing Return features in decreasing order (most spatially #' variable first). #' #' @rdname VariableFeatures #' @export #' @method SpatiallyVariableFeatures Assay #' SpatiallyVariableFeatures.Assay <- function( object, method = "moransi", decreasing = TRUE, selection.method = deprecated(), ... ) { CheckDots(...) if (is_present(arg = selection.method)) { .Deprecate( when = '5.0.0', what = 'SpatiallyVariableFeatures(selection.method = )', with = 'SpatiallyVariableFeatures(method = )' ) method <- selection.method } vf <- SVFInfo(object = object, method = method, status = TRUE) vf <- vf[rownames(x = vf)[which(x = vf[, "variable"][, 1])], ] if (!is.null(x = decreasing)) { vf <- vf[order(x = vf[, "rank"], decreasing = !decreasing), ] } return(rownames(x = vf)[which(x = vf[, "variable"][, 1])]) } #' @rdname VariableFeatures #' @export #' @method SVFInfo Assay #' SVFInfo.Assay <- function( object, method = c("markvariogram", "moransi"), status = FALSE, selection.method = deprecated(), ... ) { CheckDots(...) if (is_present(arg = selection.method)) { .Deprecate( when = '5.0.0', what = 'SVFInfo(selection.method = )', with = 'SVFInfo(method = )' ) method <- selection.method } method <- method[1] method <- match.arg(arg = method) vars <- switch( EXPR = method, markvariogram = grep( pattern = "r.metric", x = colnames(x = object[]), value = TRUE ), moransi = grep( pattern = 'moransi', x = colnames(x = object[]), value = TRUE ), abort(message = paste("Unknown method:", sQuote(x = method))) ) tryCatch( expr = svf.info <- object[[vars]], error = function(e) { stop( "Unable to find highly variable feature information for method '", method, "'", call. = FALSE ) } ) colnames(x = svf.info) <- vars if (status) { svf.info$variable <- object[[paste0(method, '.spatially.variable')]] svf.info$rank <- object[[paste0(method, '.spatially.variable.rank')]] } return(svf.info) } #' @rdname VariableFeatures #' @export #' @method VariableFeatures Assay #' VariableFeatures.Assay <- function( object, method = NULL, selection.method = deprecated(), ... ) { suppressWarnings(CheckDots(...)) if (is_present(arg = selection.method)) { .Deprecate( when = '5.0.0', what = 'VariableFeatures(selection.method = )', with = 'VariableFeatures(method = )' ) method <- selection.method } if (!is.null(x = method)) { vf <- HVFInfo( object = object, method = method, status = TRUE ) return(rownames(x = vf)[which(x = vf[, "variable"][, 1])]) } return(slot(object = object, name = 'var.features')) } #' @rdname VariableFeatures #' @export #' @method VariableFeatures<- Assay #' "VariableFeatures<-.Assay" <- function(object, ..., value) { CheckDots(...) if (!length(x = value)) { slot(object = object, name = 'var.features') <- character(length = 0) return(object) } if (any(grepl(pattern = '_', x = value))) { warning( "Feature names cannot have underscores '_', replacing with dashes '-'", call. = FALSE, immediate = TRUE ) value <- gsub(pattern = '_', replacement = '-', x = value) } value <- split(x = value, f = value %in% rownames(x = object)) if (length(x = value[['FALSE']]) > 0) { if (length(x = value[['TRUE']]) == 0) { abort(message = "None of the features provided are in this Assay object") } else { warning( "Not all features provided are in this Assay object, removing the following feature(s): ", paste(value[['FALSE']], collapse = ', '), call. = FALSE, immediate. = TRUE ) } } slot(object = object, name = 'var.features') <- value[['TRUE']] return(object) } #' @param cells Subset of cell names #' @param expression A predicate expression for feature/variable expression, #' can evaluate anything that can be pulled by \code{FetchData}; please note, #' you may need to wrap feature names in backticks (\code{``}) if dashes #' between numbers are present in the feature name #' @param invert Invert the selection of cells #' #' @importFrom stats na.omit #' #' @rdname WhichCells #' @export #' @method WhichCells Assay #' WhichCells.Assay <- function( object, cells = NULL, expression, invert = FALSE, ... ) { CheckDots(...) cells <- cells %||% colnames(x = object) if (!missing(x = expression) && !is.null(x = substitute(expr = expression))) { key.pattern <- paste0('^', Key(object = object)) expr <- if (tryCatch(expr = is_quosure(x = expression), error = function(...) FALSE)) { expression } else if (is.call(x = enquo(arg = expression))) { enquo(arg = expression) } else { parse(text = expression) } expr.char <- suppressWarnings(expr = as.character(x = expr)) expr.char <- unlist(x = lapply(X = expr.char, FUN = strsplit, split = ' ')) expr.char <- gsub( pattern = key.pattern, replacement = '', x = expr.char, perl = TRUE ) expr.char <- gsub( pattern = '(', replacement = '', x = expr.char, fixed = TRUE ) expr.char <- gsub( pattern = '`', replacement = '', x = expr.char ) vars.use <- which(x = expr.char %in% rownames(x = object)) expr.char <- expr.char[vars.use] data.subset <- FetchData(object = object, vars = expr.char) cells <- rownames(x = data.subset)[eval_tidy(expr = expr, data = data.subset)] } if (invert) { cells <- colnames(x = object)[!colnames(x = object) %in% cells] } cells <- na.omit(object = unlist(x = cells, use.names = FALSE)) return(as.character(x = cells)) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for R-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' @inherit .DollarNames.Assay5 return title details sections seealso #' #' @description Autocompletion for \code{$} access on an #' \code{\link{Assay}} object #' #' @inheritParams utils::.DollarNames #' @param x An \code{\link{Assay}} object #' #' @importFrom utils .DollarNames #' #' @keywords internal #' #' @method .DollarNames Assay #' @export #' #' @concept assay #' .DollarNames.Assay <- function(x, pattern = '') { slots.avial <- Layers(x) slots.avial <- as.list(slots.avial) names(slots.avial) <- unlist(slots.avial) return(.DollarNames(x = slots.avial, pattern = pattern)) } #' @inherit $.Assay5 return title description details sections params #' #' @param x An \code{\link{Assay}} object #' #' @method $ Assay #' @export #' #' @family assay #' #' @examples #' rna <- pbmc_small[["RNA"]] #' #' # Fetch a layer with `$` #' rna$data[1:10, 1:4] #' "$.Assay" <- function(x, i) { return(LayerData(object = x, layer = i)) } #' @rdname cash-.Assay #' #' @method $<- Assay #' @export #' #' @examples #' # Add a layer with `$` #' rna$data <- rna$counts #' rna$data[1:10, 1:4] #' "$<-.Assay" <- function(x, i, value) { LayerData(object = x, layer = i) <- value return(x) } #' @inherit [.Assay5 return title description details sections #' #' @inheritParams [.Assay5 #' @param x An \code{\link{Assay}} object #' @param j Ignored #' #' @method [ Assay #' @export #' #' @order 1 #' #' @seealso \code{\link{LayerData}} #' #' @family assay #' #' @examples #' rna <- pbmc_small[["RNA"]] #' #' # Get a vector of layer names in this assay #' rna[] #' #' # Fetch layer data #' rna["data"][1:10, 1:4] #' "[.Assay" <- function(x, i = missing_arg(), j = missing_arg(), ...) { if (getOption(x = 'Seurat.object.assay.brackets', default = 'v5') == 'v3') { if (is_missing(x = i)) { i <- seq_len(length.out = nrow(x = x)) } if (is_missing(x = j)) { j <- seq_len(length.out = ncol(x = x)) } return(LayerData( object = x, layer = DefaultLayer(object = x)[1L], cells = j, features = i )) } if (is_missing(x = i)) { return(Layers(object = x)) } return(LayerData(object = x, layer = i, ...)) } #' @inherit [[.Assay5 return title description details sections #' #' @inheritParams [[.Assay5 #' @param x An \code{\link{Assay}} object #' #' @method [[ Assay #' @export #' #' @family assay #' #' @order 1 #' #' @examples #' rna <- pbmc_small[["RNA"]] #' #' # Pull the entire feature-level meta data data frame #' head(rna[[]]) #' #' # Pull a specific column of feature-level meta data #' head(rna[["vst.mean"]]) #' head(rna[["vst.mean", drop = TRUE]]) #' "[[.Assay" <- function(x, i, ..., drop = FALSE) { if (missing(x = i)) { i <- colnames(x = slot(object = x, name = 'meta.features')) } data.return <- slot(object = x, name = 'meta.features')[, i, drop = FALSE, ...] if (drop) { data.return <- unlist(x = data.return, use.names = FALSE) names(x = data.return) <- rep.int(x = rownames(x = x), times = length(x = i)) } return(data.return) } #' @inherit dim.Assay5 return title description details sections #' #' @inheritParams [.Assay #' #' @method dim Assay #' @export #' #' @family assay #' #' @examples #' rna <- pbmc_small[["RNA"]] #' dim(rna) #' dim.Assay <- function(x) { return(dim(x = GetAssayData(object = x))) } #' @inherit dimnames.Assay5 title description details sections #' #' @inheritParams [.Assay #' #' @return \code{dimnames}: A two-length list with the following values: #' \itemize{ #' \item A character vector will all features in \code{x} #' \item A character vector will all cells in \code{x} #' } #' #' @method dimnames Assay #' @export #' #' @family assay #' @family dimnames #' #' @examples #' rna <- pbmc_small[["RNA"]] #' #' # Feature and cell names can be acquired with `rownames` and `colnames` #' head(rownames(rna)) #' head(colnames(rna)) #' dimnames.Assay <- function(x) { return(dimnames(x = GetAssayData(object = x))) } #' @param value A two-length list where the first entry is the existing feature #' names for \code{x} and the second entry is the \emph{updated} cell names #' for \code{x} #' #' @return \code{dimnames<-}: \code{x} with the cell names updated to those #' in \code{value[[2L]]} #' #' @rdname dimnames.Assay #' #' @method dimnames<- Assay #' @export #' #' @examples #' # Cell names can be updated with `colnames<-` #' colnames(rna)[1] <- "newcell" #' head(colnames(rna)) #' "dimnames<-.Assay" <- function(x, value) { op <- options(Seurat.object.validate = FALSE) on.exit(expr = options(op), add = TRUE) # Check the provided dimnames msg <- "Invalid 'dimnames' given for a Seurat object" if (!is_bare_list(x = value, n = 2L)) { abort(message = msg) } else if (!all(sapply(X = value, FUN = length) == dim(x = x))) { abort(message = msg) } value <- lapply(X = value, FUN = as.character) # Warn about changing features if (!all(value[[1L]] == rownames(x = slot(object = x, name = 'data')))) { warn(message = "Changing feature names in v3 Assays is not supported") } # Set cell names for (lyr in c('counts', 'data', 'scale.data')) { if (!IsMatrixEmpty(x = slot(object = x, name = lyr))) { suppressWarnings(expr = colnames(x = slot(object = x, name = lyr)) <- value[[2L]]) } } # Validate and return the Seurat object options(op) validObject(object = x) return(x) } #' @rdname sub-sub-.Assay #' #' @method head Assay #' @export #' #' @examples #' # `head` and `tail` can be used to quickly view feature-level meta data #' head(rna) #' head.Assay <- function(x, n = 10L, ...) { return(head(x[[]], n = 10L, ...)) } #' Merge Assays #' #' Merge one or more v3 assays together #' #' @inheritParams [[.Assay #' @param y One or more \code{\link{Assay}} objects #' @param add.cell.ids A character vector of \code{length(x = c(x, y))}; #' appends the corresponding values to the start of each objects' cell names #' @param merge.data Merge the data slots instead of just merging the counts #' (which requires renormalization); this is recommended if the same #' normalization approach was applied to all objects #' @param labels,collapse Currently unused #' #' @return A new assay with data merged from \code{c(x, y)} #' #' @method merge Assay #' @export #' #' @family assay #' merge.Assay <- function( x = NULL, y = NULL, add.cell.ids = NULL, merge.data = TRUE, labels = NULL, collapse = TRUE, ... ) { CheckDots(...) assays <- c(x, y) if (any(sapply( X = assays, FUN = function(assay.i) inherits(x = assay.i, what = "Assay5") ))) { return(merge(x = as(x, "Assay5"), y, ...)) } if (!is.null(x = add.cell.ids)) { for (i in seq_along(along.with = assays)) { assays[[i]] <- RenameCells( object = assays[[i]], new.names = add.cell.ids[i] ) } } # Merge the counts (if present) counts.mats <- lapply(X = assays, FUN = ValidateDataForMerge, slot = "counts") keys <- unlist(sapply(X = assays, FUN = Key)) merged.counts <- RowMergeSparseMatrices( mat1 = counts.mats[[1]], mat2 = counts.mats[2:length(x = counts.mats)] ) combined.assay <- CreateAssayObject( counts = merged.counts, min.cells = -1, min.features = -1 ) Key(object = combined.assay) <- keys[1] if (merge.data) { data.mats <- lapply(X = assays, FUN = ValidateDataForMerge, slot = "data") merged.data <- RowMergeSparseMatrices( mat1 = data.mats[[1]], mat2 = data.mats[2:length(x = data.mats)] ) # only keep cells that made it through counts filtering params if (!all.equal(target = colnames(x = combined.assay), current = colnames(x = merged.data))) { merged.data <- merged.data[, colnames(x = combined.assay)] } combined.assay <- SetAssayData( object = combined.assay, layer = "data", new.data = merged.data ) } return(combined.assay) } #' @inherit split.Assay5 title description details #' #' @inheritParams split.Assay5 #' @param x An \code{\link{Assay}} object #' #' @return Returns a v5 assay with splitted layers #' #' @method split Assay #' @export #' #' @family assay #' split.Assay <- function( x, f, drop = FALSE, layers = NA, ... ) { warn(message = paste( strwrap(x = paste( "Input is a v3 assay and `split()` only works for v5 assays;", "converting to a v5 assay" )) )) x <- as(object = x, Class = 'Assay5') split.x <- split( x = x, f = f, drop = drop, layers = layers, ... ) return(split.x) } #' @inherit subset.Assay5 title description details sections #' #' @inheritParams subset.Assay5 #' @param x An \code{\link{Assay}} object #' #' @return \code{x} with just the cells and features specified by #' \code{cells} and \code{features} #' #' @importFrom stats na.omit #' #' @method subset Assay #' @export #' #' @family assay #' #' @examples #' rna <- pbmc_small[["RNA"]] #' rna2 <- subset(rna, features = VariableFeatures(rna)) #' rna2 #' subset.Assay <- function(x, cells = NULL, features = NULL, ...) { CheckDots(...) cells <- cells %||% colnames(x = x) if (all(is.na(x = cells))) { cells <- colnames(x = x) } else if (any(is.na(x = cells))) { warn(message = "NAs passed in cells vector, removing NAs") cells <- na.omit(object = cells) } cells <- intersect(x = colnames(x), y = cells) features <- features %||% rownames(x = x) if (all(is.na(x = features))) { features <- rownames(x = x) } else if (any(is.na(x = features))) { warn(message = "NAs passed in the features vector, removing NAs") features <- na.omit(object = features) } if (all(sapply(X = list(features, cells), FUN = length) == dim(x = x))) { return(x) } if (is.numeric(x = features)) { features <- rownames(x = x)[features] } features <- gsub( pattern = paste0('^', Key(object = x)), replacement = '', x = features ) features <- intersect(x = features, y = rownames(x = x)) if (length(x = features) == 0) { abort(message = "Cannot find features provided") } if (ncol(x = GetAssayData(object = x, layer = 'counts')) == ncol(x = x)) { slot(object = x, name = "counts") <- GetAssayData(object = x, layer = "counts")[features, cells, drop = FALSE] } slot(object = x, name = "data") <- GetAssayData(object = x, layer = "data")[features, cells, drop = FALSE] cells.scaled <- colnames(x = GetAssayData(object = x, layer = "scale.data")) cells.scaled <- cells.scaled[cells.scaled %in% cells] cells.scaled <- cells.scaled[na.omit(object = match(x = colnames(x = x), table = cells.scaled))] features.scaled <- rownames(x = GetAssayData(object = x, layer = 'scale.data')) features.scaled <- intersect(x = features, y = features.scaled) slot(object = x, name = "scale.data") <- if (length(x = cells.scaled) > 0 && length(x = features.scaled) > 0) { GetAssayData(object = x, layer = "scale.data")[features.scaled, cells.scaled, drop = FALSE] } else { new(Class = 'matrix') } VariableFeatures(object = x) <- VariableFeatures(object = x)[VariableFeatures(object = x) %in% features] slot(object = x, name = 'meta.features') <- x[[]][features, , drop = FALSE] validObject(object = x) return(x) } #' @rdname sub-sub-.Assay #' #' @method tail Assay #' @export #' #' @examples #' tail(rna) #' tail.Assay <- function(x, n = 10L, ...) { return(tail(x[[]], n = n, ...)) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # S4 methods #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' @rdname sub-.Assay #' #' @examples #' # Set layer data #' rna["data"] <- rna["counts"] #' rna["data"][1:10, 1:4] #' setMethod( f = '[<-', signature = c(x = 'Assay', i = 'character'), definition = function(x, i, ..., value) { LayerData(object = x, layer = i, ...) <- value return(x) } ) #' @rdname sub-sub-.Assay #' #' @order 2 #' setMethod( f = '[[<-', signature = c(x = 'Assay'), definition = function(x, i, ..., value) { meta.data <- x[[]] feature.names <- rownames(x = meta.data) if (is.data.frame(x = value)) { value <- lapply( X = 1:ncol(x = value), FUN = function(index) { v <- value[[index]] names(x = v) <- rownames(x = value) return(v) } ) } err.msg <- "Cannot add more or fewer meta.features information without values being named with feature names" if (length(x = i) > 1) { # Add multiple bits of feature-level metadata value <- rep_len(x = value, length.out = length(x = i)) for (index in 1:length(x = i)) { names.intersect <- intersect(x = names(x = value[[index]]), feature.names) if (length(x = names.intersect) > 0) { meta.data[names.intersect, i[index]] <- value[[index]][names.intersect] } else if (length(x = value) %in% c(nrow(x = meta.data), 1) %||% is.null(x = value)) { meta.data[i[index]] <- value[index] } else { stop(err.msg, call. = FALSE) } } } else { # Add a single column to feature-level metadata value <- unlist(x = value) if (length(x = intersect(x = names(x = value), y = feature.names)) > 0) { meta.data[, i] <- value[feature.names] } else if (length(x = value) %in% c(nrow(x = meta.data), 1) || is.null(x = value)) { meta.data[, i] <- value } else { stop(err.msg, call. = FALSE) } } slot(object = x, name = 'meta.features') <- meta.data return(x) } ) #' @rdname sub-sub-.Assay #' setMethod( f = '[[<-', signature = c( x = 'Assay', i = 'missing', j = 'missing', value = 'data.frame' ), definition = function(x, ..., value) { # Allow removing all meta data if (IsMatrixEmpty(x = value)) { x[[names(x = x[[]])]] <- NULL return(x) } if (is.null(names(x = value))) { warn(message = 'colnames of input cannot be NULL') } else { # If no `i` provided, use the column names from value x[[names(x = value)]] <- value } return(x) } ) #' Row and Column Sums and Means #' #' Calculate \code{\link{rowSums}}, \code{\link{colSums}}, #' \code{\link{rowMeans}}, and \code{\link{colMeans}} on \code{Assay} objects #' #' @inheritParams [[.Assay #' @inheritParams Matrix::colMeans #' @param slot Name of assay expression matrix to calculate column/row #' means/sums on #' #' @return \code{colMeans}: The column (cell-wise) means of \code{slot} #' #' @importFrom Matrix colMeans #' #' @keywords internal #' #' @export #' #' @concept assay #' #' @seealso \code{\link{Assay}} #' #' @examples #' rna <- pbmc_small[["RNA"]] #' #' colMeans(rna) #' setMethod( f = 'colMeans', signature = c(x = 'Assay'), definition = function(x, na.rm = FALSE, dims = 1, ..., slot = 'data') { return(Matrix::colMeans( x = GetAssayData(object = x, layer = slot), na.rm = na.rm, dims = dims, ... )) } ) #' @return \code{colSums}: The column (cell-wise) sums of \code{slot} #' #' @rdname colMeans-Assay-method #' #' @importFrom Matrix colSums #' #' @export #' #' @examples #' colSums(rna) #' setMethod( f = 'colSums', signature = c(x = 'Assay'), definition = function(x, na.rm = FALSE, dims = 1, ..., slot = 'data') { return(Matrix::colSums( x = GetAssayData(object = x, layer = slot), na.rm = na.rm, dims = dims, ... )) } ) #' @return \code{rowMeans}: The row (feature-wise) means of \code{slot} #' #' @rdname colMeans-Assay-method #' #' @importFrom Matrix rowMeans #' #' @export #' #' @examples #' rowMeans(rna) #' setMethod( f = 'rowMeans', signature = c(x = 'Assay'), definition = function(x, na.rm = FALSE, dims = 1, ..., slot = 'data') { return(Matrix::rowMeans( x = GetAssayData(object = x, layer = slot), na.rm = na.rm, dims = dims, ... )) } ) #' @return \code{rowSums}: The row (feature-wise) sums of \code{slot} #' #' @rdname colMeans-Assay-method #' #' @importFrom Matrix rowSums #' #' @export #' #' @examples #' rowSums(rna) #' setMethod( f = 'rowSums', signature = c(x = 'Assay'), definition = function(x, na.rm = FALSE, dims = 1, ..., slot = 'data') { return(Matrix::rowSums( x = GetAssayData(object = x, layer = slot), na.rm = na.rm, dims = dims, ... )) } ) #' V3 Assay Overview #' #' Overview of an \code{\link{Assay}} object #' #' @template return-show #' #' @keywords internal #' #' @concept assay #' #' @seealso \code{\link{Assay}} #' #' @examples #' rna <- pbmc_small[["RNA"]] #' rna #' setMethod( f = 'show', signature = 'Assay', definition = function(object) { cat( class(x = object)[1], 'data with', nrow(x = object), 'features for', ncol(x = object), 'cells\n' ) if (length(x = VariableFeatures(object = object)) > 0) { top.ten <- head(x = VariableFeatures(object = object), n = 10L) top <- 'Top' variable <- 'variable' } else { top.ten <- head(x = rownames(x = object), n = 10L) top <- 'First' variable <- '' } features <- paste0( variable, ' feature', if (length(x = top.ten) != 1) { 's' }, ":\n" ) features <- gsub(pattern = '^\\s+', replacement = '', x = features) cat( top, length(x = top.ten), features, paste(strwrap(x = paste(top.ten, collapse = ', ')), collapse = '\n'), '\n' ) return(invisible(x = NULL)) } ) #' V3 Assay Validity #' #' @templateVar cls Assay #' @template desc-validity #' #' @section \code{data} Validation: #' blah #' #' @section \code{counts} Validation: #' blah #' #' @section \code{scale.data} Validation: #' blah #' #' @section Feature-Level Meta Data Validation: #' blah #' #' @section Variable Feature Validation: #' blah #' #' @inheritSection Key-validity Key Validation #' #' @name Assay-validity #' #' @family assay #' @seealso \code{\link[methods]{validObject}} #' #' @examples #' rna <- pbmc_small[["RNA"]] #' validObject(rna) #' setValidity( Class = 'Assay', method = function(object) { if (.GetSeuratCompat() < '5.0.0') { return(TRUE) } if (isFALSE(x = getOption(x = "Seurat.object.validate", default = TRUE))) { warn( message = paste("Not validating", class(x = object)[1L], "objects"), class = 'validationWarning' ) return(TRUE) } valid <- NULL # Check matrices features <- rownames(x = slot(object = object, name = 'data')) if (anyDuplicated(x = features)) { valid <- c(valid, "duplicate feature names are not allowed") } cells <- colnames(x = slot(object = object, name = 'data')) if (anyDuplicated(x = cells)) { valid <- c(valid, "duplicate cell names are not allowed") } for (lyr in c('counts', 'scale.data')) { ldat <- slot(object = object, name = lyr) if (IsMatrixEmpty(x = ldat)) { next } if (!all(colnames(x = ldat) == cells)) { valid <- c( valid, paste0("'", lyr, "' must have the same cells as 'data'") ) } if (lyr == 'counts' && !all(rownames(x = ldat) == features)) { valid <- c( valid, paste0("'", lyr, "' must have the same features as 'data'") ) } else if (lyr == 'scale.data') { scaled <- rownames(x = ldat) if (!all(scaled %in% features)) { valid <- c( valid, "all features in 'scale.data' must be present in 'data'" ) } else if (is.unsorted(x = MatchCells(new = scaled, orig = features, ordered = TRUE))) { valid <- c( valid, "features in 'scale.data' must be in the same order as in 'data'" ) } } } # Check meta.features mf <- slot(object = object, name = 'meta.features') if (nrow(x = mf) != length(x = features)) { valid <- c( valid, "'meta.features' must have the same number of rows as 'data'" ) } else if (!all(row.names(x = mf) == features)) { valid <- c(valid, "meta.features' must have the same features as 'data'") } # Check variable features vf <- slot(object = object, name = 'var.features') if (length(x = vf) && !all(vf %in% features)) { valid <- c(valid, "all 'var.features' must be present in") } # TODO: Check assay.orig return(valid %||% TRUE) } ) #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Internal #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' Calculate nCount and nFeature #' #' @param object An \code{\link{Assay}} object #' #' @return A named list with nCount and nFeature #' #' @keywords internal #' #' @noRd #' #' @examples #' \donttest{ #' calcn <- SeuratObject:::CalcN(pbmc_small[["RNA"]]) #' head(as.data.frame(calcn)) #' } #' CalcN <- .CalcN #' Subset cells in vst data #' #' @param sct.info A vst.out list #' @param cells vector of cells to retain #' @param features vector of features to retain #' #' @keywords internal #' #' @noRd #' SubsetVST <- function(sct.info, cells, features) { cells.keep <- intersect(x = cells, y = rownames(x = sct.info$cell_attr)) sct.info$cell_attr <- sct.info$cell_attr[cells.keep, ] # find which subset of features are in the SCT assay feat.keep <- intersect(x = features, y = rownames(x = sct.info$gene_attr)) sct.info$gene_attr <- sct.info$gene_attr[feat.keep, ] return(sct.info) } #' Validate Assay Data for Merge #' #' Pulls the proper data matrix for merging assay data. If the slot is empty, #' will return an empty matrix with the proper dimensions from one of the #' remaining data slots. #' #' @param assay Assay to pull data from #' @param slot Slot to pull from #' #' @return Returns the data matrix if present (i.e.) not 0x0. Otherwise, #' returns an appropriately sized empty sparse matrix #' #' @importFrom methods as #' @importFrom Matrix Matrix #' #' @keywords internal #' #' @noRd #' ValidateDataForMerge <- function(assay, slot) { mat <- GetAssayData(object = assay, layer = slot) if (any(dim(x = mat) == c(0, 0))) { slots.to.check <- setdiff(x = c("counts", "data", "scale.data"), y = slot) for (ss in slots.to.check) { data.dims <- dim(x = GetAssayData(object = assay, layer = ss)) data.slot <- ss if (!any(data.dims == c(0, 0))) { break } } if (any(data.dims == c(0, 0))) { stop("The counts, data, and scale.data slots are all empty for the provided assay.") } mat <- Matrix( data = 0, nrow = data.dims[1], ncol = data.dims[2], dimnames = dimnames(x = GetAssayData(object = assay, layer = data.slot)) ) mat <- as.sparse(x = mat) } return(mat) } SeuratObject/R/layers.R0000644000176200001440000002357714520004144014477 0ustar liggesusers#' @include zzz.R #' @importFrom methods as callNextMethod #' NULL #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% setGeneric( name = '.GetLayerData', def = function(x, ...) { standardGeneric(f = '.GetLayerData') }, signature = c('x') ) setGeneric( name = '.PrepLayerData', def = function(x, target, transpose = NULL, ...) { standardGeneric(f = '.PrepLayerData') }, signature = c('x', 'target') ) #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Functions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for Seurat-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for R-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Internal #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% .CheckDimnames <- function(dnames, dims) { if (is.null(x = dnames)) { return(NULL) } if (!is.numeric(x = dims)) { stop("'dims' must be a numeric vector", call. = FALSE) } else if (!is.list(x = dnames) || length(x = dnames) != length(x = dims)) { stop("'dnames' must be a list of length ", length(x = dims), call. = FALSE) } dims <- dims %/% 1L didx <- match( x = vapply( X = dnames, FUN = length, FUN.VALUE = numeric(length = 1L), USE.NAMES = FALSE ), table = dims ) didx[duplicated(x = didx)] <- NA didx[is.na(x = didx)] <- setdiff( x = seq_along(along.with = dims), y = didx ) return(dnames[didx]) } #' Check Feature Margin #' #' @param fmargin Either \code{1} or \code{2} #' #' @return \code{fmargin} #' #' @keywords internal #' #' @export #' #' @examples #' .CheckFmargin(1L) #' .CheckFmargin(2.3) #' #' # Error if `fmargin` is outside of [1:2] #' if (FALSE) { #' .CheckFmargin(3L) #' } #' .CheckFmargin <- function(fmargin) { fmargin <- fmargin %/% 1L if (!fmargin %in% seq.int(from = 1L, to = 2L)) { abort(message = paste(sQuote(x = fmargin), "must be either 1 or 2")) } return(fmargin) } .Cmargin <- function(fmargin) { fmargin <- .CheckFmargin(fmargin = fmargin) return(setdiff(x = seq.int(from = 1L, to = 2L), y = fmargin)) } #' Get and Prepare Layer Data #' #' Assemble layer data pulled from and prepare layer data for addition to #' v5 assays; v5 assays allow layers to be in multiple formats and support #' both regular and transposed orientations #' #' When transposition is required, \code{.GetLayerData2} and #' \code{.PrepLayerData2} will attempt to #' \link[.GetMethod]{determine the optimal method} of \code{\link[base:t]{t()}} #' to use; if no optimal method is found, \code{base::t.default} will be used #' for transposition, which may be slow #' #' @param x A matrix-like object #' @param dnames An optional list with feature and cell names #' (in order for \code{.GetLayerData2}) #' @param fmargin Margin for features (1 or 2); for \code{.GetLayerData2}, if #' \code{fmargin} is 2, \code{x} will be transposed (see details) #' #' @return \code{.GetLayerData2}: \code{x}, potentially transposed and #' potentially with \code{dnames} set as the \code{\link{dimnames}} #' #' @keywords internal #' #' @noRd #' .GetLayerData2 <- function(x, dnames = NULL, fmargin = 1L) { # Check dimnames if (!is.null(x = dnames)) { ndims <- length(x = dim(x = x)) if (!is_bare_list(x = dnames, n = ndims)) { abort(message = paste("'dnames' must be a list of length", ndims)) } didx <- match( x = sapply(X = dnames, FUN = length, USE.NAMES = FALSE), table = dim(x = x) ) didx[duplicated(x = didx)] <- NA didx[is.na(x = didx)] <- setdiff(x = seq_len(length.out = ndims), y = didx) dnames <- dnames[didx] } # Check fmargin fmargin <- fmargin %/% 1L if (!fmargin %in% c(1L, 2L)) { abort(message = "'fmargin' must be either 1 or 2") } # Do we transpose if (fmargin == 2L) { tf <- .GetMethod(fxn = 't', cls = class(x = x)) x <- tf(x) dnames <- rev(x = dnames) } suppressWarnings(expr = suppressMessages(expr = dimnames(x = x) <- dnames)) return(x) } #' @param target An optional two-length integer vector with dimensions of #' the v5 assay that \code{x} will be added to; used only if #' \code{transpose} is \code{NULL} #' @param transpose Transpose \code{x} before returning it; if \code{NULL} and #' \code{target} is provided, will attempt to determine if transposition is #' necessary (see details) #' #' @return \code{.PrepLayerData2}: \code{x} with \code{\link{dimnames}} removed #' and \code{dnames} added as attributes \dQuote{\code{features}} and #' \dQuote{\code{cells}} and potentially transposed #' #' @rdname dot-GetLayerData2 #' #' @keywords internal #' #' @noRd #' .PrepLayerData2 <- function( x, target = NULL, transpose = FALSE, dnames = NULL, fmargin = 1L ) { if (is.null(x = x)) { return(x) } # Check fmargin fmargin <- fmargin %/% 1L if (!fmargin %in% c(1L, 2L)) { abort(message = "'fmargin' must be either 1 or 2") } cmargin <- c(2L, 1L)[fmargin] # Auto-check transposition if (!is.null(x = target) && is.null(x = transpose)) { if (!is_bare_integerish(x = target, n = 2L, finite = TRUE)) { abort(message = "'target' must be a two-length integer vector") } xdim <- dim(x)[c(fmargin, cmargin)] if (all(rev(xdim) == target)) { transpose <- TRUE } } # Check dimnames if (is.null(x = dnames)) { dnames <- dimnames(x = x) } else if (!is_bare_list(x = dnames, n = 2L)) { abort(message = "'dnames' must be a two-length list") } # Handle transposition if (isTRUE(x = transpose)) { tf <- .GetMethod(fxn = 't', cls = class(x = x)) x <- tf(x) dnames <- rev(x = dnames) } x <- suppressMessages(expr = unname(x)) attr(x = x, which = 'features') <- dnames[[fmargin]] attr(x = x, which = 'cells') <- dnames[[cmargin]] return(x) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # S4 methods #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% setMethod( f = '.GetLayerData', signature = c(x = 'ANY'), definition = function(x, dnames = NULL, fmargin = 1L, ...) { dnames <- .CheckDimnames(dnames = dnames, dims = dim(x = x)) fmargin <- .CheckFmargin(fmargin = fmargin) if (fmargin == 2L) { x <- base::t(x = x) dnames <- rev(x = dnames) } dimnames(x = x) <- dnames return(x) } ) setMethod( f = '.GetLayerData', signature = c(x = 'data.frame'), definition = function(x, dnames = NULL, fmargin = 1L, ...) { x <- callNextMethod() return(as.data.frame(x = x)) } ) #' @importFrom Matrix t #' @importClassesFrom Matrix Matrix #' setMethod( f = '.GetLayerData', signature = c(x = 'Matrix'), definition = function(x, dnames = NULL, fmargin = 1L, ...) { dnames <- .CheckDimnames(dnames = dnames, dims = dim(x = x)) fmargin <- .CheckFmargin(fmargin = fmargin) if (fmargin == 2L) { x <- Matrix::t(x = x) dnames <- rev(x = dnames) } dimnames(x = x) <- dnames return(x) } ) #' @importFrom spam t #' @importClassesFrom spam spam #' setMethod( f = '.GetLayerData', signature = c(x = 'spam'), definition = function(x, fmargin = 1L, ...) { fmargin <- .CheckFmargin(fmargin = fmargin) if (fmargin == 2L) { x <- spam::t(x = x) } return(x) } ) setMethod( f = '.PrepLayerData', signature = c(x = 'ANY', target = 'numeric'), definition = function( x, target, transpose = NULL, dnames = NULL, fmargin = 1L, ... ) { # Check the value of target # target should be c(nfeatures, ncells) if (length(x = target) != 2L) { stop("'target' must be a two-length numeric vector", call. = FALSE) } # If transpose is NULL, try to determine if we should transpose if (is.null(x = transpose)) { fmargin <- .CheckFmargin(fmargin = fmargin) cmargin <- .Cmargin(fmargin = fmargin) xdim <- dim(x = x)[c(fmargin, cmargin)] if (all(rev(x = xdim) == target)) { transpose <- TRUE } } return(.PrepLayerData( x = x, target = NULL, transpose = transpose, dnames = dnames, fmargin = fmargin, ... )) } ) setMethod( f = '.PrepLayerData', signature = c(x = 'ANY', target = 'NULL'), definition = function( x, target, transpose = NULL, dnames = NULL, fmargin = 1L, tf = base::t, ... ) { fmargin <- .CheckFmargin(fmargin = fmargin) cmargin <- .Cmargin(fmargin = fmargin) if (isTRUE(x = transpose)) { x <- tf(x) dnames <- rev(x = dnames) } x <- suppressMessages(expr = unname(x)) attr(x = x, which = 'features') <- dnames[[fmargin]] attr(x = x, which = 'cells') <- dnames[[cmargin]] return(x) } ) #' @importFrom Matrix t #' @importClassesFrom Matrix Matrix #' setMethod( f = '.PrepLayerData', signature = c(x = 'Matrix', target = 'NULL'), definition = function(x, target, transpose = NULL, ...) { return(callNextMethod( x = x, target = target, transpose = transpose, tf = Matrix::t, ... )) } ) setMethod( f = '.PrepLayerData', signature = c(x = 'NULL', target = 'ANY'), definition = function(x, target, transpose = NULL, ...) { return(x) } ) #' @importFrom spam t #' @importClassesFrom spam spam #' setMethod( f = '.PrepLayerData', signature = c(x = 'spam', target = 'NULL'), definition = function(x, target, transpose = NULL, ...) { return(callNextMethod( x = x, target = target, transpose = transpose, tf = spam::t, ... )) } ) SeuratObject/R/assay5.R0000644000176200001440000025336214525215076014417 0ustar liggesusers#' @include zzz.R #' @include assay.R #' @include layers.R #' @include logmap.R #' @include keymixin.R #' @importFrom methods callNextMethod setAs #' NULL #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Class definitions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' Core Assay Infrastructure #' #' The \code{StdAssay} class is a virtual class that provides core #' infrastructure for assay data in \pkg{Seurat}. Assays contain expression #' data (layers) and associated feature-level meta data. Derived classes #' (eg. \link[=Assay5]{the v5 Assay}) may optionally #' define additional functionality #' #' @template slot-stdassay #' @template slot-misc #' @template slot-key #' #' @keywords internal #' #' @exportClass StdAssay #' #' @aliases StdAssay #' #' @family stdassay #' #' @seealso \code{\link{Assay5-class}} \code{\link{Assay5T-class}} #' setClass( Class = 'StdAssay', contains = c('VIRTUAL', 'KeyMixin'), slots = c( layers = 'list', cells = 'LogMap', features = 'LogMap', default = 'integer', assay.orig = 'character', meta.data = 'data.frame', misc = 'list' ) ) #' The v5 \code{Assay} Object #' #' The v5 \code{Assay} is the typical \code{Assay} class used in \pkg{Seurat} #' v5; ... #' #' @template slot-stdassay #' @template slot-misc #' @template slot-key #' #' @exportClass Assay5 #' #' @aliases Assay5 #' #' @family assay5 #' setClass( Class = 'Assay5', contains = 'StdAssay' ) #' The Transposed v5 \code{Assay} Object #' #' @template slot-stdassay #' @template slot-misc #' @template slot-key #' #' @template lifecycle-experimental #' #' @keywords internal #' #' @aliases Assay5T #' setClass( Class = 'Assay5T', contains = 'StdAssay' ) #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Functions #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' Create a v5 Assay object #' #' Create an \code{\link{Assay5}} object from a feature expression matrix; #' the expected format of the matrix is features x cells #' #' @inheritParams .CreateStdAssay #' @param data Optional prenormalized data matrix #' @template param-dots-method # @param transpose Create a transposed assay # @param ... Extra parameters passed to \code{\link{.CreateStdAssay}} #' #' @return An \code{\link{Assay5}} object #' #' @export #' #' @concept assay #' CreateAssay5Object <- function( counts = NULL, data = NULL, min.cells = 0, min.features = 0, csum = NULL, fsum = NULL, ... ) { transpose <- FALSE colsums <- Matrix::colSums rowsums <- Matrix::rowSums type <- 'Assay5' csum <- csum %||% colsums fsum <- fsum %||% rowsums counts <- CheckLayersName(matrix.list = counts, layers.type = 'counts') data <- CheckLayersName(matrix.list = data, layers.type = 'data') if (!is.null(x = counts) & !is.null(data)) { counts.cells <- unlist( x = lapply( X = counts, FUN = function(x) colnames(x = x) ) ) data.cells <- unlist( x = lapply( X = data, FUN = function(x) colnames(x) ) ) if (!all(counts.cells == data.cells)) { abort(message = 'counts and data input should have the same cells') } } counts <- c(counts, data) data <- NULL CheckGC() return(.CreateStdAssay( counts = counts, min.cells = min.cells, min.features = min.features, transpose = transpose, type = type, csum = csum, fsum = fsum, ... )) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for Seurat-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' @method .AssayClass Assay5T #' @export #' .AssayClass.Assay5T <- function(object) { return('Transposed Assay (v5)') } #' @method .CalcN StdAssay #' @export #' .CalcN.StdAssay <- function(object, layer = 'counts', simplify = TRUE, ...) { layer <- tryCatch( expr = Layers(object = object, search = layer), error = \(...) NULL ) # %||% DefaultLayer(object = object) if (is.null(x = layer)) { warn( message = "Cannot find the layer(s) specified", class = 'missingLayerWarning' ) return(NULL) } calcn <- vector(mode = 'list', length = length(x = layer)) names(x = calcn) <- layer for (lyr in layer) { ldat <- LayerData(object = object, layer = lyr) if (IsMatrixEmpty(x = ldat)) { next } calcn[[lyr]] <- .CalcN(object = ldat) } calcn <- Filter(f = length, x = calcn) # If every layer is empty, return `NULL` if (!length(x = calcn)) { return(NULL) } else if (isFALSE(x = simplify)) { # If we're not simplifying, return the list as-is return(calcn) } else if (length(x = calcn) == 1L) { # If we're only calculating N for one layer, return those results return(calcn[[1L]]) } # Simplify the calcn list for all cells all.cells <- Cells(x = object, layer = layer, simplify = TRUE) ncells <- length(x = all.cells) ncalc <- list( nCount = vector(mode = 'numeric', length = ncells), nFeature = vector(mode = 'numeric', length = ncells) ) names(x = ncalc$nCount) <- names(x = ncalc$nFeature) <- all.cells # For every layer, add the nCount and nFeature counts to existing cells for (i in seq_along(along.with = calcn)) { lcells <- names(x = calcn[[i]][['nCount']]) ncalc[['nCount']][lcells] <- calcn[[i]][['nCount']] + ncalc[['nCount']][lcells] ncalc[['nFeature']][lcells] <- calcn[[i]][['nFeature']] + ncalc[['nFeature']][lcells] } return(ncalc) } #' @method .CalcN default #' @export #' .CalcN.default <- function(object, ...) { return(list( nCount = Matrix::colSums(x = object), nFeature = Matrix::colSums(x = object > 0) )) } #' @param layer Name of layer to store \code{counts} as #' #' @rdname dot-CreateStdAssay #' @method .CreateStdAssay default #' @export #' .CreateStdAssay.default <- function( counts, min.cells = 0, min.features = 0, cells = NULL, features = NULL, transpose = FALSE, type = 'Assay5', layer = 'counts', ... ) { if (!is_bare_integerish(x = dim(x = counts), n = 2L, finite = TRUE)) { abort(message = "'counts' must be a two-dimensional object") } dnames <- dimnames(x = counts) cls <- class(x = counts) if (isTRUE(x = transpose)) { csum <- .GetMethod(fxn = 'rowSums', cls = cls) cells <- cells %||% dnames[[1L]] fsum <- .GetMethod(fxn = 'colSums', cls = cls) features <- features %||% dnames[[2L]] } else { csum <- .GetMethod(fxn = 'colSums', cls = cls) cells <- cells %||% dnames[[2L]] fsum <- .GetMethod(fxn = 'rowSums', cls = cls) features <- features %||% dnames[[1L]] } counts <- list(counts) names(x = counts) <- layer return(.CreateStdAssay( counts = counts, min.cells = min.cells, layer = layer, min.features = min.features, cells = cells, features = features, transpose = transpose, type = type, fsum = fsum, csum = csum, ... )) } #' @param csum Function for calculating cell sums #' @param fsum Function for calculating feature sums #' #' @importFrom methods getClass #' @importFrom utils getS3method methods #' #' @rdname dot-CreateStdAssay #' @method .CreateStdAssay list #' @export #' .CreateStdAssay.list <- function( counts, min.cells = 0, min.features = 0, cells = NULL, features = NULL, transpose = FALSE, type = 'Assay5', csum = Matrix::colSums, fsum = Matrix::rowSums, ... ) { # Figure out feature/cell MARGINs cdef <- getClass(Class = type) contains <- names(x = slot(object = cdef, name = 'contains')) if (!'StdAssay' %in% contains) { stop("Class '", type, "' does not inherit from StdAssay") } for (i in c(type, contains, 'default')) { fmargin <- getS3method(f = '.MARGIN', class = i, optional = TRUE) if (is.function(x = fmargin)) { break } } cdim <- fmargin(object = type, type = 'cells') fdim <- fmargin(object = type, type = 'features') counts <- lapply(X = counts, FUN = function(x) { x <- CheckFeaturesNames(data = x) return(x) }) # Check cell/feature names for all layers if (is.atomic(x = cells) || is.null(x = cells)) { cells <- rep_len(x = list(cells), length.out = length(x = counts)) } if (!is_bare_list(x = cells) || length(x = cells) != length(x = counts)) { stop("Not enough cells for the counts matrices provided", call. = FALSE) } cells <- .CheckNames(x = cells, n = names(x = counts)) if (is.atomic(x = features) || is.null(x = features)) { features <- rep_len(x = list(features), length.out = length(x = counts)) } if (!is_bare_list(x = features) || length(x = features) != length(x = counts)) { stop("Not enough features for the counts matrices provided", call. = FALSE) } features <- .CheckNames(x = features, n = names(x = counts)) for (layer in names(x = counts)) { cells[[layer]] <- cells[[layer]] %||% dimnames(x = counts[[layer]])[[cdim]] %||% paste0('Cell_', seq_len(length.out = dim(x = counts[[layer]])[cdim])) features[[layer]] <- features[[layer]] %||% dimnames(x = counts[[layer]])[[fdim]] %||% paste0('Feature', seq_len(length.out = dim(x = counts[[layer]])[fdim])) } # Filter based on min.features if (min.features > 0) { for (layer in names(x = counts)) { if (inherits(x = counts[[layer]], what = "IterableMatrix")) { check_installed(pkg = 'BPCells', reason = 'for working with BPCells') col_stat <- BPCells::matrix_stats(matrix = counts[[layer]], col_stats = 'nonzero')$col_stats cells.use <- which(x = col_stat >= min.features) } else { cells.use <- which(x = csum(counts[[layer]] > 0) >= min.features) } counts[[layer]] <- if (cdim == 1L) { counts[[layer]][cells.use, ] } else { counts[[layer]][, cells.use] } cells[[layer]] <- cells[[layer]][cells.use] } } # For now, coerce to dgCMatrix if not dgCMatrix, IterableMatrix, or DelayedArray if (!inherits(x = counts[[layer]], what = c('dgCMatrix', 'IterableMatrix', 'DelayedArray'))) { warning('Data is of class ', class(counts[[layer]])[1], ". Coercing to dgCMatrix.", call. = FALSE, immediate. = TRUE) if (inherits(x = counts[[layer]], what = "data.frame")) { counts[[layer]] <- as.sparse(x = counts[[layer]], ...) } else { counts[[layer]] <- as.sparse(x = counts[[layer]]) } } # Filter based on min.cells if (min.cells > 0) { for (layer in names(x = counts)) { if (inherits(x = counts[[layer]], what = "IterableMatrix")) { check_installed(pkg = 'BPCells', reason = 'for working with BPCells') row_stat <- BPCells::matrix_stats(matrix = counts[[layer]], row_stats = 'nonzero')$row_stats features.use <- which(x = row_stat >= min.cells) } else { features.use <- which(x = fsum(counts[[layer]] > 0) >= min.cells) } counts[[layer]] <- if (fdim == 1L) { counts[[layer]][features.use, ] } else { counts[[layer]][, features.use] } features[[layer]] <- features[[layer]][features.use] } } features.all <- Reduce(f = union, x = features) cells.all <- Reduce(f = union, x = cells) calcN_option <- getOption( x = 'Seurat.object.assay.calcn', default = Seurat.options$Seurat.object.assay.calcn ) # Create the object object <- new( Class = type, layers = list(), default = 0L, features = LogMap(y = features.all), cells = LogMap(y = cells.all), meta.data = EmptyDF(n = length(x = features.all)), misc = list(calcN = calcN_option %||% TRUE), ... ) for (layer in names(x = counts)) { LayerData( object = object, layer = layer, features = features[[layer]], cells = cells[[layer]], transpose = transpose ) <- counts[[layer]] } DefaultLayer(object = object) <- Layers(object = object)[1L] validObject(object = object) return(object) } #' @rdname dot-CreateStdAssay #' @method .CreateStdAssay Matrix #' @export #' .CreateStdAssay.Matrix <- function( counts, min.cells = 0, min.features = 0, cells = NULL, features = NULL, transpose = FALSE, type = 'Assay5', layer = 'counts', ... ) { counts <- list(counts) names(x = counts) <- layer if (isTRUE(x = transpose)) { csum <- Matrix::rowSums fsum <- Matrix::colSums } else { csum <- Matrix::colSums fsum <- Matrix::rowSums } return(.CreateStdAssay( counts = counts, layer = layer, min.cells = min.cells, min.features = min.features, cells = cells, features = features, transpose = transpose, type = type, csum = csum, fsum = fsum, ... )) } #' @rdname dot-CreateStdAssay #' @method .CreateStdAssay matrix #' @export #' .CreateStdAssay.matrix <- .CreateStdAssay.Matrix #' @method .MARGIN Assay5T #' @export #' .MARGIN.Assay5T <- function(x, type = c('features', 'cells'), ...) { type <- type[1] type <- match.arg(arg = type) return(unname(obj = c(features = 2L, cells = 1L)[type])) } #' @method .SelectFeatures StdAssay #' @export #' .SelectFeatures.StdAssay <- function(object, ...) { .NotYetImplemented() } #' @templateVar fxn AddMetaData #' @template method-stdassay #' #' @method AddMetaData StdAssay #' @export #' AddMetaData.StdAssay <- AddMetaData.Assay #' @rdname AddMetaData #' @method AddMetaData Assay5 #' @export #' AddMetaData.Assay5 <- AddMetaData.StdAssay #' @templateVar fxn CastAssay #' @template method-stdassay #' #' @importFrom methods as #' @importFrom rlang quo_get_env quo_get_expr #' #' @method CastAssay StdAssay #' @export #' CastAssay.StdAssay <- function(object, to, layers = NA, verbose = TRUE, ...) { layers <- Layers(object = object, search = layers) if (is_quosure(x = to)) { to <- eval( expr = quo_get_expr(quo = to), envir = quo_get_env(quo = to) ) } stopifnot(is.character(x = to) || is.function(x = to)) for (lyr in layers) { if (isTRUE(x = verbose)) { msg <- paste("Attempting to cast layer", lyr) if (is.character(x = to)) { msg <- paste(msg, "to", to) } message(msg) } clyr <- Cells(x = object, layer = lyr) flyr <- Features(x = object, layer = lyr) w <- function(e) { warn(message = paste0( "Unable to cast layer ", sQuote(x = lyr), ": ", e$message )) return(invisible(x = NULL)) } if (is.function(x = to)) { tryCatch( expr = LayerData( object = object, layer = lyr, cells = clyr, features = flyr ) <- to(LayerData(object = object, layer = lyr, fast = TRUE), ...), error = w ) } else { check <- is( object = LayerData(object = object, layer = lyr, fast = TRUE), class2 = to ) if (isTRUE(x = check)) { next } tryCatch( expr = LayerData( object = object, layer = lyr, cells = clyr, features = flyr ) <- as( object = LayerData(object = object, layer = lyr, fast = TRUE), Class = to ), error = w ) } } return(object) } #' @template param-verbose #' @param layers A vector of layers to cast; defaults to all layers #' #' @rdname CastAssay #' @method CastAssay Assay5 #' @export #' CastAssay.Assay5 <- CastAssay.StdAssay #' @templateVar fxn Cells #' @template method-stdassay #' #' @method Cells StdAssay #' @export #' Cells.StdAssay <- function(x, layer = NULL, simplify = TRUE, ...) { if (any(is.na(x = layer)) || is.null(x = layer)) { return(rownames(x = slot(object = x, name = 'cells'))) } layer <- Layers(object = x, search = layer) cells <- sapply( X = layer, FUN = function(lyr) { return(slot(object = x, name = 'cells')[[lyr]]) }, simplify = FALSE, USE.NAMES = TRUE ) if (isFALSE(x = simplify)) { return(cells) } return(Reduce(f = union, x = cells)) } #' @param layer Layer to pull cells/features for; defaults to default layer; #' if \code{NA}, returns all cells for the assay #' @param simplify Simplify the cell/feature names into a single vector; if #' \code{FALSE}, separates each cell/feature names by layer #' #' @rdname Cells #' @method Cells Assay5 #' @export #' Cells.Assay5 <- Cells.StdAssay #' @templateVar fxn DefaultAssay #' @template method-stdassay #' #' @method DefaultAssay StdAssay #' @export #' DefaultAssay.StdAssay <- function(object, ...) { return(slot(object = object, name = 'assay.orig')) } #' @rdname DefaultAssay #' @method DefaultAssay Assay5 #' @export #' DefaultAssay.Assay5 <- DefaultAssay.StdAssay #' @rdname DefaultAssay-StdAssay #' @method DefaultAssay<- StdAssay #' @export #' "DefaultAssay<-.StdAssay" <- function(object, ..., value) { slot(object = object, name = 'assay.orig') <- value return(object) } #' @rdname DefaultAssay #' @method DefaultAssay<- Assay5 #' @export #' "DefaultAssay<-.Assay5" <- `DefaultAssay<-.StdAssay` #' @templateVar fxn DefaultLayer #' @template method-stdassay #' #' @method DefaultLayer StdAssay #' @export #' DefaultLayer.StdAssay <- function(object, ...) { idx <- slot(object = object, name = 'default') if (!length(x = idx) || idx == 0L) { idx <- 1L } return(Layers(object = object)[seq_len(length.out = idx)]) } #' @rdname DefaultLayer #' @method DefaultLayer Assay5 #' @export #' DefaultLayer.Assay5 <- DefaultLayer.StdAssay #' @rdname DefaultLayer-StdAssay #' @method DefaultLayer<- StdAssay #' @export #' "DefaultLayer<-.StdAssay" <- function(object, ..., value) { layers <- Layers(object = object) value <- Layers(object = object, search = value) idx <- MatchCells(new = layers, orig = value, ordered = TRUE) slot(object = object, name = 'layers') <- c( slot(object = object, name = 'layers')[idx], slot(object = object, name = 'layers')[-idx] ) slot(object = object, name = 'default') <- length(x = value) validObject(object = object) return(object) } #' @rdname DefaultLayer #' @method DefaultLayer<- Assay5 #' @export #' "DefaultLayer<-.Assay5" <- `DefaultLayer<-.StdAssay` #' @rdname Cells-StdAssay #' @method Features StdAssay #' @export #' Features.StdAssay <- function(x, layer = NULL, simplify = TRUE, ...) { if (any(is.na(x = layer)) || is.null(x = layer)) { return(rownames(x = slot(object = x, name = 'features'))) } layer <- Layers(object = x, search = layer) features <- sapply( X = layer, FUN = function(lyr) { return(slot(object = x, name = 'features')[[lyr]]) }, simplify = FALSE, USE.NAMES = TRUE ) if (isFALSE(x = simplify)) { return(features) } return(Reduce(f = union, x = features)) } #' @rdname Cells #' @method Features Assay5 #' @export #' Features.Assay5 <- Features.StdAssay #' @method FetchData StdAssay #' @export #' FetchData.StdAssay <- function( object, vars, cells = NULL, layer = NULL, clean = TRUE, ... ) { # Identify layer(s) to use layer.set <- rev(x = Layers( object = object, search = layer %||% 'data' )) if (is.null(layer) && length(layer.set) == 1 && layer.set == 'scale.data'){ warning('Default search for "data" layer yielded no results; utilizing "scale.data" layer instead.') } if (is.null(layer.set) & is.null(layer) ) { warning('data layer is not found and counts layer is used') layer.set <- rev(x = Layers( object = object, search = 'counts' )) } if (is.null(layer.set)) { stop('layer "', layer,'" is not found in the object') } else { layer <- layer.set } # Identify cells to use cells <- cells %||% colnames(x = object) if (is.numeric(x = cells)) { cells <- colnames(x = object)[cells] } cells <- intersect(x = cells, y = colnames(x = object)) if (!length(x = cells)) { abort(message = "None of the cells requested found in this assay") } # Check vars orig <- vars vars <- gsub( pattern = paste0('^', Key(object = object)), replacement = '', x = vars ) # Pull expression information features <- sapply( X = layer, FUN = Features, x = object, simplify = FALSE, USE.NAMES = TRUE ) vars <- intersect(x = vars, y = Reduce(f = union, x = features)) data.fetched <- as.data.frame(x = matrix( data = NA_real_, nrow = length(x = cells), ncol = length(x = vars), dimnames = list(cells, vars) )) for (lyr in layer) { lcells <- intersect(x = cells, y = Cells(x = object, layer = lyr)) lvars <- intersect(x = vars, y = Features(x = object, layer = lyr)) if (!length(x = lcells) || !length(x = lvars)) { next } data.fetched[lcells, lvars] <- as(t(x = LayerData( object = object, layer = lyr, cells = lcells, features = lvars )[lvars, lcells, drop = FALSE]), "matrix") } # Clean out missing cells from the expression matrix if (isTRUE(x = clean)) { no.data <- which(x = apply( X = data.fetched, MARGIN = 1L, FUN = function(x) { return(all(is.na(x = x))) } )) if (length(x = no.data)) { warn(message = paste( "Removing", length(x = no.data), "cells missing data for features requested" )) data.fetched <- data.fetched[-no.data, , drop = FALSE] } } # Add keys to keyed vars keyed.features <- paste0(Key(object = object), colnames(x = data.fetched)) keyed.idx <- which(x = keyed.features %in% orig) if (length(x = keyed.idx)) { colnames(x = data.fetched)[keyed.idx] <- keyed.features[keyed.idx] } # Check final list of features fetched <- setdiff(x = unlist(x = dimnames(x = data.fetched)), y = cells) missing <- setdiff(x = orig, y = fetched) if (length(x = missing) == length(x = orig)) { abort(message = "None of the requested variables found", class = 'varsNotFoundError') } else if (length(x = missing)) { warn(message = paste( "The following variables could not be found:", paste(missing, collapse = ', ') )) } return(data.fetched) # # Pull feature-level metadata # meta.fetch <- c( # grep(pattern = '^md_', x = vars, value = TRUE), # vars[vars %in% colnames(x = object[[]])] # ) # meta.fetch <- setdiff(x = meta.fetch, y = colnames(x = data.fetched)) # meta.keyed <- which(x = grepl(pattern = '^md', x = meta.fetch)) # meta.fetch <- gsub(pattern = '^md_', replacement = '', x = meta.fetch) # meta.data <- lapply( # X = meta.fetch, # FUN = function(x, f) { # df <- as.data.frame(x = matrix( # data = NA, # nrow = 1L, # ncol = length(x = f), # dimnames = list(x, f) # )) # df[x, ] <- object[[x]][f, , drop = TRUE] # return(df) # }, # f = colnames(x = data.fetched) # ) # meta.data <- do.call(what = 'rbind', args = meta.data) # if (length(x = meta.keyed)) { # rownames(x = meta.data)[meta.keyed] <- paste0( # 'md_', # rownames(x = meta.data)[meta.keyed] # ) # } # keyed.meta <- paste0(Key(object = object), rownames(x = meta.data)) # keyed.meta.idx <- which(x = keyed.meta %in% orig) # if (length(x = keyed.meta.idx)) { # rownames(x = meta.data)[keyed.meta.idx] <- keyed.meta[keyed.meta.idx] # } # if (nrow(x = data.fetched) && (nrow(x = meta.data) %||% 0)) { # warning( # "Returning both expression and meta data; data types might be different than expected", # call. = FALSE, # immediate. = TRUE # ) # } # data.fetched <- rbind(data.fetched, meta.data) # # Add keys to keyed vars # keyed.features <- paste0(Key(object = object), colnames(x = data.fetched)) # keyed.idx <- which(x = keyed.features %in% orig) # if (length(x = keyed.idx)) { # colnames(x = data.fetched)[keyed.idx] <- keyed.features[keyed.idx] # } # # Check final list of features # fetched <- setdiff(x = unlist(x = dimnames(x = data.fetched)), y = cells) # missing <- setdiff(x = orig, y = fetched) # if (length(x = missing) == length(x = orig)) { # stop("None of the requested variables found", call. = FALSE) # } else if (length(x = missing)) { # warning( # "The following variables could not be found: ", # paste(missing, collapse = ', '), # call. = FALSE, # immediate. = TRUE # ) # } # return(data.fetched) } #' @method FetchData Assay5 #' @export #' FetchData.Assay5 <- FetchData.StdAssay #' @templateVar fxn AssayData #' @template method-stdassay #' #' @method GetAssayData StdAssay #' @export #' GetAssayData.StdAssay <- function( object, layer = NULL, slot = deprecated(), ... ) { CheckDots(..., fxns = LayerData) if (is_present(arg = slot)) { .Deprecate( when = '5.0.0', what = 'GetAssayData(slot = )', with = 'GetAssayData(layer = )' ) layer <- slot } layer_name <- layer[1L] %||% DefaultLayer(object = object)[1L] layer.set <- suppressWarnings(expr = Layers( object = object, search = layer %||% 'data' )) if (is.null(layer.set) & is.null(layer)) { warning('data layer is not found and counts layer is used') layer <- rev(x = Layers( object = object, search = 'counts' )) } else { layer <- layer.set } if (length(x = layer) > 1) { abort("GetAssayData doesn't work for multiple layers in v5 assay.", " You can run 'object <- JoinLayers(object = object, layers = layer)'.") } if (is.null(x = layer)) { msg <- paste("Layer", sQuote(x = layer_name), "is empty") opt <- getOption(x = "Seurat.object.assay.v3.missing_layer", default = Seurat.options$Seurat.object.assay.v3.missing_layer) opt <- tryCatch(expr = arg_match0( arg = opt, values = c("matrix","null", "error")), error = function(...) { return(Seurat.options$Seurat.object.assay.v3.missing_layer) } ) if (opt == "error") { abort(message = msg) } warn(message = msg) return(switch( EXPR = opt, matrix = switch( EXPR = layer_name, scale.data = new(Class = "matrix"), new(Class = "dgCMatrix") ), NULL)) } return(LayerData(object = object, layer = layer, ...)) } #' @templateVar fxn VariableFeatures #' @template method-stdassay #' #' @importFrom utils adist #' #' @method HVFInfo StdAssay #' @export #' HVFInfo.StdAssay <- function( object, method = NULL, status = FALSE, layer = NULL, strip = TRUE, ... ) { # Find available HVF methods and layers vf.methods.layers <- .VFMethodsLayers(object = object, type = 'hvf') #vf.methods <- .VFMethods(object = object, type = 'hvf') #vf.layers <- .VFLayers(object = object, type = 'hvf') # Determine which method and layer to use method <- method[length(methods)] %||% names(vf.methods.layers[length(vf.methods.layers)]) method <- switch( EXPR = tolower(x = method), mean.var.plot = 'mvp', dispersion = 'disp', method ) method <- tryCatch( expr = match.arg(arg = method, choices = names(vf.methods.layers)), error = function(...) { return(NULL) } ) # If no methods found, return NULL if (is.null(x = method)) { return(method) } vf.methods.layers <- unlist(vf.methods.layers, use.names = FALSE) layer <- Layers(object = object, search = layer) layer <- vf.methods.layers[which.min(x = adist(x = layer, y = vf.methods.layers))] # Find the columns for the specified method and layer cols <- grep( pattern = paste0(paste('^vf', method, layer, sep = '_'), '_'), x = colnames(x = object[[]]), value = TRUE ) if (!isTRUE(x = status)) { cols <- setdiff( x = cols, y = paste('vf', method, layer, c('variable', 'rank'), sep = '_') ) } hvf.info <- object[[cols]] colnames(x = hvf.info) <- gsub( pattern = '^vf_', replacement = '', x = colnames(x = hvf.info) ) if (isTRUE(x = strip)) { colnames(x = hvf.info) <- gsub( pattern = paste0(paste(method, layer, sep = '_'), '_'), replacement = '', x = colnames(x = hvf.info) ) } return(hvf.info) } #' @param layer Layer to pull variable features for #' @param strip Remove method/layer identifiers from highly variable data frame #' #' @rdname VariableFeatures #' @method HVFInfo Assay5 #' @export #' HVFInfo.Assay5 <- HVFInfo.StdAssay #' @method JoinLayers StdAssay #' @export #' JoinLayers.StdAssay <- function( object, layers = NULL, new = NULL, ... ) { layers <- layers %||% c('counts', 'data', 'scale.data') new <- new %||% layers if (length(x = layers) != length(x = new)) { stop('Number of layers and new should be the same') } var.features <- VariableFeatures(object = object) for (i in seq_along(layers)) { num.layers <- suppressWarnings( expr = length(x = Layers(object = object, search = layers[i])) ) if (num.layers > 0L) { object <- JoinSingleLayers( object = object, layers = layers[i], new = new[i], default = TRUE, ... ) } } VariableFeatures(object = object) <- var.features return(object) } #' @param layers Names of layers to split or join #' @param new Name of new layers #' #' @rdname SplitLayers #' #' @method JoinLayers Assay5 #' @export #' JoinLayers.Assay5 <- JoinLayers.StdAssay #' @rdname Key #' @method Key Assay5 #' @export #' Key.Assay5 <- .Key #' @rdname Key #' @method Key<- Assay5 #' @export #' "Key<-.Assay5" <- `.Key<-` #' @templateVar fxn Layers #' @template method-stdassay #' #' @method LayerData StdAssay #' @export #' LayerData.StdAssay <- function( object, layer = NULL, cells = NULL, features = NULL, fast = FALSE, slot = deprecated(), ... ) { if (is_present(arg = slot)) { deprecate_stop( when = '5.0.0', what = 'LayerData(slot = )', with = 'LayerData(layer = )"' ) } layer_name <- layer[1L] %||% DefaultLayer(object = object)[1L] # Identify layer(s) to use layer.set <- suppressWarnings(expr = Layers( object = object, search = layer %||% 'data' )) # If layer.set doesnt return anything and layer is not defined if (is.null(layer.set) & is.null(layer) ) { warning( 'data layer is not found and counts layer is used', call. = F, immediate. = T ) layer <- Layers( object = object, search = 'counts' ) } else { layer <- layer.set } if (length(x = layer) > 1) { warning("multiple layers are identified by ", paste0(layer, collapse = ' '), "\n only the first layer is used") layer <- layer[1L] } # layer <- match.arg(arg = layer, choices = Layers(object = object)) if (is.null(x = layer) || any(is.na(x = layer))) { msg <- paste("Layer", sQuote(x = layer_name), "is empty") opt <- getOption(x = "Seurat.object.assay.v3.missing_layer", default = Seurat.options$Seurat.object.assay.v3.missing_layer) opt <- tryCatch(expr = arg_match0( arg = opt, values = c("matrix","null", "error")), error = function(...) { return(Seurat.options$Seurat.object.assay.v3.missing_layer) } ) if (opt == "error") { abort(message = msg) } warn(message = msg) return(switch( EXPR = opt, matrix = switch( EXPR = layer_name, scale.data = new(Class = "matrix"), new(Class = "dgCMatrix") ), NULL)) } # Allow cell/feature subsets dnames <- list( Features(x = object, layer = layer), Cells(x = object, layer = layer) ) cells <- cells %||% dnames[[2L]] if (is.numeric(x = cells)) { cells <- dnames[[2L]][cells] } cells <- sort(x = MatchCells( new = dnames[[2L]], orig = cells, ordered = TRUE )) dnames[[2L]] <- dnames[[2L]][cells] features <- features %||% dnames[[1L]] if (is.numeric(x = features)) { features <- dnames[[1L]][features] } features <- sort(x = MatchCells( new = dnames[[1L]], orig = features, ordered = TRUE )) dnames[[1L]] <- dnames[[1L]][features] if(length(x = dnames[[1L]]) == 0) { stop('features are not found') } # Pull the layer data ldat <- if (.MARGIN(x = object) == 1L) { methods::slot(object = object, name = 'layers')[[layer]][features, cells, drop = FALSE] } else { methods::slot(object = object, name = 'layers')[[layer]][cells, features, drop = FALSE] } # Add dimnames and transpose if requested ldat <- if (isTRUE(x = fast)) { ldat } else if (is_na(x = fast)) { .GetLayerData2(x = ldat, dnames = dnames, fmargin = 1L) # .GetLayerData( # x = ldat, # dnames = dnames, # fmargin = 1L, # ... # ) } else { .GetLayerData2( x = ldat, dnames = dnames, fmargin = .MARGIN(x = object, type = 'features') ) # .GetLayerData( # x = ldat, # dnames = dnames, # fmargin = .MARGIN(x = object, type = 'features'), # ... # ) } return(ldat) } #' @param features,cells Vectors of features/cells to include #' @param fast Determine how to return the layer data; choose from: #' \describe{ #' \item{\code{FALSE}}{Apply any transpositions and attempt to add #' feature/cell names (if supported) back to the layer data} #' \item{\code{NA}}{Attempt to add feature/cell names back to the layer data, #' skip any transpositions} #' \item{\code{TRUE}}{Do not apply any transpositions or add feature/cell #' names to the layer data} #' } #' #' @rdname Layers #' @method LayerData Assay5 #' @export #' LayerData.Assay5 <- LayerData.StdAssay #' #' @rdname Layers-StdAssay #' @method LayerData<- StdAssay #' @export #' "LayerData<-.StdAssay" <- function( object, layer, features = NULL, cells = NULL, ..., value ) { if (!is_scalar_character(x = layer) || !nzchar(x = layer)) { abort(message = "'layer' must be a single non-empty string") } # Remove a layer if (is.null(x = value)) { if (length(x = Layers(object = object)) == 1L) { stop("Cannot remove only layer") } else if (layer %in% DefaultLayer(object = object)) { msg <- 'Removing default layer' if (length(x = DefaultLayer(object = object)) == 1L) { DefaultLayer(object = object) <- Layers(object = object)[2] msg <- paste0( msg, ', setting default to ', DefaultLayer(object = object) ) } else { didx <- slot(object = object, name = 'default') - 1L slot(object = object, name = 'default') <- didx } warning(msg, call. = FALSE, immediate. = TRUE) } slot(object = object, name = 'layers')[[layer]] <- NULL if (slot(object = object, name = 'default') > length(x = Layers(object = object)) || !length(x = slot(object = object, name = 'default'))) { slot(object = object, name = 'default') <- length(x = Layers(object = object)) } maps <- c( 'cells', 'features' ) for (i in maps) { slot(object = object, name = i)[[layer]] <- NULL } validObject(object = object) return(object) } # Add a layer fdim <- .MARGIN(x = object, type = 'features') cdim <- .MARGIN(x = object, type = 'cells') # Assume input matrix is features x cells dnames <- list( features %||% dimnames(x = value)[[1L]], cells %||% dimnames(x = value)[[2L]] ) if (length(x = unique(x = dim(x = value))) > 1L) { didx <- match( x = vapply( X = dnames, FUN = length, FUN.VALUE = numeric(length = 1L), USE.NAMES = FALSE ), table = dim(x = value) ) dnames <- dnames[didx] } value <- .PrepLayerData2( x = value, target = dim(x = object), dnames = dnames, fmargin = fdim, ... ) # value <- .PrepLayerData( # x = value, # target = dim(x = object), # dnames = dnames, # fmargin = fdim, # ... # ) # Check features and cells features <- attr(x = value, which = 'features') %||% seq_len(length.out = dim(x = value)[fdim]) cells <- attr(x = value, which = 'cells') %||% seq_len(length.out = dim(x = value)[cdim]) fmatch <- MatchCells( new = features, orig = rownames(x = slot(object = object, name = 'features')), ordered = TRUE ) cmatch <- MatchCells( new = cells, orig = rownames(x = slot(object = object, name = 'cells')), ordered = TRUE ) if (is.null(x = fmatch)) { stop( "No feature overlap between existing object and new layer data", call. = FALSE ) } else if (is.null(x = cmatch)) { stop( "No cell overlap between existing object and new layer data", call. = FALSE ) } features <- features[fmatch] cells <- cells[cmatch] # Check for existing layer data if (layer %in% Layers(object = object)) { fcheck <- if (is.numeric(x = features)) { Features(x = object, layer = layer)[features] } else { features } ccheck <- if (is.numeric(x = cells)) { Cells(x = object, layer = layer)[cells] } else { cells } if (!identical(x = fcheck, y = Features(x = object, layer = layer))) { warning( "Different features in new layer data than already exists for ", layer, call. = FALSE, immediate. = TRUE ) } if (!identical(x = ccheck, y = Cells(x = object, layer = layer))) { warning( "Different cells in new layer data than already exists for ", layer, call. = FALSE, immediate. = TRUE ) } } # Reorder the layer data value <- if (fdim == 1L) { value[fmatch, cmatch] } else { value[cmatch, fmatch] } # Add the layer slot(object = object, name = 'layers')[[layer]] <- value # Update the maps slot(object = object, name = 'features')[[layer]] <- features slot(object = object, name = 'cells')[[layer]] <- cells validObject(object = object) return(object) } #' @rdname Layers #' @method LayerData<- Assay5 #' @export #' "LayerData<-.Assay5" <- `LayerData<-.StdAssay` #' @rdname Layers-StdAssay #' @method Layers StdAssay #' @export #' Layers.StdAssay <- function(object, search = NA, ...) { if (is.null(x = search)) { return(DefaultLayer(object = object)) } layers <- names(x = slot(object = object, name = 'layers')) if (!is_na(x = search)) { layers <- unique(x = unlist(x = lapply( X = search, FUN = function(lyr) { if (lyr %in% layers) { return(lyr) } patterns <- c(paste0('^', lyr), paste0(lyr, '$'), lyr) res <- vector(mode = 'character') for (p in patterns) { res <- grep(pattern = p, x = layers, value = TRUE, ...) if (length(x = res)) { break } } return(res) } ))) if (!length(x = layers)) { warning(message = "No layers found matching search pattern provided", call. = FALSE, immediate. = TRUE) return(NULL) } } return(layers) } #' @param search A pattern to search layer names for; pass one of: #' \itemize{ #' \item \dQuote{\code{NA}} to pull all layers #' \item \dQuote{\code{NULL}} to pull the default layer(s) #' \item a \link[base:grep]{regular expression} that matches layer names #' } #' #' @rdname Layers #' @method Layers Assay5 #' @export #' Layers.Assay5 <- Layers.StdAssay #' @templateVar fxn Misc #' @template method-stdassay #' #' @method Misc StdAssay #' @export #' Misc.StdAssay <- .Misc #' @rdname Misc #' @method Misc Assay5 #' @export #' Misc.Assay5 <- .Misc #' @templateVar fxn Misc #' @template method-stdassay #' #' @method Misc<- StdAssay #' @export #' "Misc<-.StdAssay" <- `.Misc<-` #' @rdname Misc #' @method Misc<- Assay5 #' @export #' "Misc<-.Assay5" <- `.Misc<-` #' @templateVar fxn RenameCells #' @template method-stdassay #' #' @method RenameCells StdAssay #' @export #' RenameCells.StdAssay <- function(object, new.names = NULL, ...) { CheckDots(...) colnames(object) <- new.names[colnames(object)] return(object) } #' @rdname RenameCells #' @method RenameCells Assay5 #' @export #' RenameCells.Assay5 <- RenameCells.StdAssay #' @rdname AssayData-StdAssay #' @method SetAssayData StdAssay #' @export #' SetAssayData.StdAssay <- function( object, layer, new.data, slot = deprecated(), ... ) { if (is_present(arg = slot)) { .Deprecate( when = '5.0.0', what = 'SetAssayData(slot = )', with = 'SetAssayData(layer = )' ) layer <- slot } LayerData(object = object, layer = layer) <- new.data return(object) } #' @rdname VariableFeatures-StdAssay #' @method VariableFeatures StdAssay #' @export #' VariableFeatures.StdAssay <- function( object, method = NULL, layer = NA, simplify = TRUE, nfeatures = Inf, selection.method = deprecated(), ... ) { if (is_present(arg = selection.method)) { .Deprecate( when = '5.0.0', what = 'VariableFeatures(selection.method = )', with = 'VariableFeatures(method = )' ) method <- selection.method } nfeatures <- nfeatures %||% Inf if ("var.features" %in% colnames(object[[]])) { if ("var.features.rank" %in% colnames(object[[]])) { var.features <- row.names(x = object[[]])[which(!is.na(object[[]]$var.features.rank))] var.features <- var.features[order(object[[]][["var.features.rank"]][which(!is.na(object[[]]$var.features))])] } else { var.features <- as.vector(object["var.features", drop = TRUE]) var.features <- var.features[!is.na(var.features)] } if (isTRUE(x = simplify) & (is.null(x = layer) || any(is.na(x = layer))) & (is.infinite(x = nfeatures) || length(x = var.features) == nfeatures)) { return(var.features) } } msg <- 'No variable features found' layer.orig <- layer methods <- .VFMethodsLayers(object = object, type = 'hvf', layers = layer) layer <- Layers(object = object, search = layer) method <- method %||% names(x = methods)[length(x = methods)] method <- match.arg(arg = method, choices = names(x = methods)) if (is_na(x = layer.orig) || is.null(x = layer.orig)) { layer <- unlist(methods[method], use.names = FALSE) } vf <- sapply( X = layer, FUN = function(lyr) { hvf.info <- HVFInfo( object = object, method = method, layer = lyr, status = TRUE, strip = TRUE ) if (is.null(x = hvf.info)) { return(NULL) } else if (!'variable' %in% names(x = hvf.info)) { return(NA) } vf <- row.names(x = hvf.info)[which(x = hvf.info$variable)] if ('rank' %in% names(x = hvf.info)) { vf <- vf[order(hvf.info$rank[which(x = hvf.info$variable)])] } else { warn(message = paste0( "No variable feature rank found for ", sQuote(x = lyr), ", returning features in assay order" )) } }, simplify = FALSE, USE.NAMES = TRUE ) if (is.null(x = unlist(x = vf))) { return(NULL) } else if (all(is.na(x = unlist(x = vf)))) { abort(message = msg) } if (isTRUE(x = simplify)) { vf <- .SelectFeatures( object = vf, all.features = intersect( x = slot(object = object, name = 'features')[,layer] ), nfeatures = nfeatures ) } return(vf) # hvf.info <- HVFInfo( # object = object, # method = method, # layer = layer, # status = TRUE, # strip = TRUE # ) # if (is.null(x = hvf.info)) { # warning(msg, call. = FALSE, immediate. = TRUE) # return(NULL) # } # if (!'variable' %in% names(x = hvf.info)) { # stop(msg, call. = FALSE) # } # vf <- rownames(x = hvf.info)[which(x = hvf.info$variable)] # if ('rank' %in% names(x = hvf.info)) { # vf <- vf[order(hvf.info$rank[which(x = hvf.info$variable)])] # } else { # warning( # "No variable feature rank found, returning features in assay order", # call. = FALSE, # immediate. = TRUE # ) # } # return(vf) } #' @param simplify When pulling for multiple layers, combine into a single #' vector and select a common set of variable features for all layers #' @param nfeatures Maximum number of features to select when simplifying #' #' @rdname VariableFeatures #' @method VariableFeatures Assay5 #' @export #' VariableFeatures.Assay5 <- VariableFeatures.StdAssay #' @rdname VariableFeatures-StdAssay #' @method VariableFeatures<- StdAssay #' @export #' "VariableFeatures<-.StdAssay" <- function( object, method = 'custom', layer = NULL, ..., value ) { if (!length(x = value)) { return(object) } value <- intersect(x = value, y = rownames(x = object)) if (!length(x = value)) { stop("None of the features specified are present in this assay", call. = FALSE) } object[['var.features']] <- value # add rank object[['var.features.rank']] <- NA object[[]][row.names(object[[]]) %in% value,]$var.features.rank <- match(row.names(object[[]])[row.names(object[[]]) %in% value], value) # layer <- Layers(object = object, search = layer) # df <- data.frame(TRUE, seq_along(along.with = value), row.names = value) # for (lyr in layer) { # names(x = df) <- paste('vf', method, lyr, c('variable', 'rank'), sep = '_') # object[] <- df # } return(object) } #' @rdname VariableFeatures #' @method VariableFeatures<- Assay5 #' @export #' "VariableFeatures<-.Assay5" <- `VariableFeatures<-.StdAssay` #' @method WhichCells StdAssay #' @export #' WhichCells.StdAssay <- WhichCells.Assay # WhichCells.StdAssay <- function( # object, # cells = NULL, # expression = missing_arg(), # invert = FALSE, # ... # ) { # cells <- cells %||% colnames(x = object) # if (!is_missing(x = expression) && !is.null(x = substitute(expr = expression))) { # key.pattern <- paste0('^', Key(object = object)) # expr <- if (tryCatch(expr = is_quosure(x = expression), error = \(...) FALSE)) { # expression # } else if (is.call(x = enquo(arg = expression))) { # enquo(arg = expression) # } else { # parse(text = expression) # } # expr.char <- suppressWarnings(expr = as.character(x = expr)) # expr.char <- unlist(x = lapply(X = expr.char, FUN = strsplit, split = ' ')) # expr.char <- gsub( # pattern = key.pattern, # replacement = '', # x = expr.char, # perl = TRUE # ) # expr.char <- gsub( # pattern = '(', # replacement = '', # x = expr.char, # fixed = TRUE # ) # expr.char <- gsub( # pattern = '`', # replacement = '', # x = expr.char # ) # } # if (isTRUE(x = invert)) { # cells <- setdiff(x = colnames(x = object), y = cells) # } # cells <- '' # return(as.character(x = cells)) # } #' @method WhichCells Assay5 #' @export #' WhichCells.Assay5 <- WhichCells.StdAssay #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for R-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' @inherit .DollarNames.Assay5 params return title description details sections #' #' @importFrom utils .DollarNames #' #' @keywords internal #' @method .DollarNames StdAssay #' @export #' #' @family stdassay #' .DollarNames.StdAssay <- function(x, pattern = '') { layers <- as.list(x = Layers(object = x)) names(x = layers) <- unlist(x = layers) return(.DollarNames(x = layers, pattern = pattern)) } #' Dollar-sign Autocompletion #' #' Autocompletion for \code{$} access on an \code{\link{Assay5}} object #' #' @inheritParams [.Assay5 #' @inheritParams utils::.DollarNames #' #' @return The layer name matches for \code{pattern} #' #' @importFrom utils .DollarNames #' #' @keywords internal #' #' @method .DollarNames Assay5 #' @export #' #' @concept assay5 #' #' @seealso \code{\link[utils:.DollarNames]{utils::.DollarNames}} #' .DollarNames.Assay5 <- .DollarNames.StdAssay #' @inherit $.Assay5 params return title description details sections #' #' @keywords internal #' @method $ StdAssay #' @export #' #' @family stdassay #' "$.StdAssay" <- function(x, i) { return(LayerData(object = x, layer = i)) } #' Layer Data #' #' Get and set layer data #' #' @inheritParams [.Assay5 #' #' @return {$}: Layer data for layer \code{i} #' #' @method $ Assay5 #' @export #' #' @family assay5 #' "$.Assay5" <- `$.StdAssay` #' @rdname cash-.StdAssay #' #' @method $<- StdAssay #' @export #' "$<-.StdAssay" <- `$<-.Assay` #' @return \code{$<-}: \code{x} with layer data \code{value} saved as \code{i} #' #' @rdname cash-.Assay5 #' #' @method $<- Assay5 #' @export #' "$<-.Assay5" <- `$<-.StdAssay` #' @inherit [.Assay5 params return title description details sections #' #' @keywords internal #' @method [ StdAssay #' @export #' #' @family stdassay #' "[.StdAssay" <- `[.Assay` #' Layer Data #' #' Get and set layer data #' #' @inheritParams [[.Assay5 #' @param i Name of layer data to get or set #' @param ... Arguments passed to \code{\link{LayerData}} #' #' @return \code{[}: The layer data for layer \code{i} #' #' @method [ Assay5 #' @export #' #' @family assay5 #' #' @seealso \code{\link{LayerData}} #' #' @order 1 #' "[.Assay5" <- `[.StdAssay` #' @inherit [[.Assay5 params return title description details sections #' #' @keywords internal #' @method [[ StdAssay #' @export #' #' @family stdassay #' "[[.StdAssay" <- function(x, i, j, ..., drop = FALSE) { if (missing(x = i)) { i <- colnames(x = slot(object = x, name = 'meta.data')) } data.return <- slot(object = x, name = 'meta.data')[, i, drop = FALSE, ...] if (nrow(x = data.return) == 0) { return(data.return) } row.names(x = data.return) <- rownames(x = x) if (isTRUE(x = drop)) { data.return <- unlist(x = data.return, use.names = FALSE) names(x = data.return) <- rep.int( x = rownames(x = x), times = length(x = i) ) } return(data.return) } #' Feature-Level Meta Data #' #' Get and set feature-level meta data #' #' @param x An \code{\link{Assay5}} object #' @param i Name of feature-level meta data to fetch or add #' @param j Ignored #' @param drop See \code{\link{drop}} #' @template param-dots-ignored #' #' @return \code{[[}: The feature-level meta data for \code{i} #' #' @method [[ Assay5 #' @export #' #' @family assay5 #' #' @order 1 #' "[[.Assay5" <- `[[.StdAssay` #' @inherit dim.Assay5 params return title description details sections #' #' @keywords internal #' @method dim StdAssay #' @export #' #' @family stdassay #' dim.StdAssay <- function(x) { return(vapply( X = c('features', 'cells'), FUN = function(s) { return(nrow(x = slot(object = x, name = s))) }, FUN.VALUE = numeric(length = 1L), USE.NAMES = FALSE )) } #' Feature and Cell Numbers #' #' @inheritParams [[.Assay5 #' #' @return A two-length numeric vector with the total number of #' features and cells in \code{x} #' #' @method dim Assay5 #' @export #' #' @family assay5 #' dim.Assay5 <- dim.StdAssay #' @inherit dimnames.Assay5 params return title description details sections #' #' @keywords internal #' @method dimnames StdAssay #' @export #' #' @seealso \code{\link{Cells}} \code{\link{Features}} #' @family stdassay #' dimnames.StdAssay <- function(x) { return(list(Features(x = x, layer = NA), Cells(x = x, layer = NA))) } #' Assay-Level Feature and Cell Names #' #' Get and set feature and cell names in v5 Assays #' #' @inheritParams [[.Assay5 #' #' @return \code{dimnames}: A two-length list with the following values: #' \itemize{ #' \item A character vector with all features in \code{x} #' \item A character vector with all cells in \code{x} #' } #' #' @method dimnames Assay5 #' @export #' #' @family assay5 #' @family dimnames #' dimnames.Assay5 <- dimnames.StdAssay #' @rdname dimnames.StdAssay #' #' @method dimnames<- StdAssay #' @export #' "dimnames<-.StdAssay" <- function(x, value) { msg <- "Invalid 'dimnames' given for an assay" if (!is_bare_list(x = value, n = 2L)) { stop(msg, call. = FALSE) } else if (!all(sapply(X = value, FUN = length) == dim(x = x))) { stop(msg, call. = FALSE) } value <- lapply(X = value, FUN = as.character) rownames(x = slot(object = x, name = 'features')) <- value[[1L]] rownames(x = slot(object = x, name = 'cells')) <- value[[2L]] validObject(object = x) return(x) } #' @param value A two-length list with updated feature and/or cells names #' #' @return \code{dimnames<-}: \code{x} with the feature and/or cell #' names updated to \code{value} #' #' @rdname dimnames.Assay5 #' #' @method dimnames<- Assay5 #' @export #' "dimnames<-.Assay5" <- `dimnames<-.StdAssay` #' @rdname sub-sub-.StdAssay #' #' @method head StdAssay #' @export #' head.StdAssay <- head.Assay #' @param n Number of meta data rows to show #' #' @return \code{head}: The first \code{n} rows of feature-level meta data #' #' @rdname sub-sub-.Assay5 #' #' @method head Assay5 #' @export #' head.Assay5 <- head.StdAssay #' @inherit merge.Assay5 params return title description details sections #' #' @note All assays must be of the same type; merging different v5 assays (eg. #' \code{\link{Assay5}} and \code{\link{Assay5T}}) is currently unsupported #' #' @keywords internal #' @method merge StdAssay #' @export #' merge.StdAssay <- function( x, y, labels = NULL, add.cell.ids = NULL, collapse = FALSE, ... ) { assays <- c(x, y) for (i in seq_along(assays)) { if (inherits(x = assays[[i]], what = 'Assay')) { assays[[i]] <- as(object = assays[[i]], Class = "Assay5") # TODO: support Assay5T } } labels <- labels %||% as.character(x = seq_along(along.with = assays)) # add.cell.ids <- add.cell.ids %||% labels # TODO: Support collapsing layers if (isTRUE(x = collapse)) { abort(message = "Collapsing layers is not yet supported") } for (i in seq_along(along.with = assays)) { if (is_na(x = labels[i])) { labels[i] <- as.character(x = i) } if (is_na(x = add.cell.ids[i])) { add.cell.ids[i] <- as.character(x = i) } if (!is.null(x = add.cell.ids[i])) { colnames(x = assays[[i]]) <- paste( colnames(x = assays[[i]]), add.cell.ids[i], sep = '.' ) } } features.all <- LogMap(y = Reduce( f = union, x = lapply(X = assays, FUN = rownames) )) combined <- new( Class = class(x = x), layers = list(), cells = LogMap(y = Reduce( f = union, x = lapply(X = assays, FUN = colnames) )), features = features.all, meta.data = EmptyDF(n = nrow(x = features.all)), misc = list(), key = Key(object = x) %||% character(length = 0L) ) # Add layers # TODO: Support collapsing layers if (isTRUE(x = collapse)) { abort(message = "Collapsing layers is not yet supported") } else { # Get default layer as default of first assay default <- DefaultLayer(assays[[1]]) for (i in seq_along(along.with = assays)) { for (lyr in Layers(object = assays[[i]])) { LayerData( object = combined, layer = paste(lyr, labels[i], sep = '.'), features = Features(x = assays[[i]], layer = lyr), cells = Cells(x = assays[[i]], layer = lyr) ) <- LayerData(object = assays[[i]], layer = lyr, fast = TRUE) } } } # Add feature-level metadata for (i in seq_along(along.with = assays)) { # Rename HVF columns mf <- assays[[i]][[]] if (!ncol(x = mf)) { next } for (type in c('vf')) { vf.idx <- grep(pattern = paste0('^', type, '_'), x = names(x = mf)) if (length(x = vf.idx)) { names(x = mf)[vf.idx] <- vapply( X = names(x = mf)[vf.idx], FUN = function(vf) { vf <- unlist(x = strsplit(x = vf, split = '_')) vf <- paste( paste(vf[1:2], collapse = '_'), paste( paste(vf[3:(length(x = vf) - 1L)], collapse = '_'), labels[i], sep = '.' ), vf[length(x = vf)], sep = '_' ) }, FUN.VALUE = character(length = 1L) ) } } combined[[]] <- mf } # TODO: Add misc DefaultLayer(combined) <- Layers(object = combined, search = default) validObject(object = combined) return(combined) } #' Merge Assays #' #' Merge one or more v5 assays together #' #' \strong{Note}: collapsing layers is currently not supported #' #' @inheritParams [.Assay5 #' @template param-dots-ignored #' @param y One or more \code{\link{Assay5}} objects #' @param labels A character vector equal to the number of objects; defaults to #' \code{as.character(seq_along(c(x, y)))} #' @param add.cell.ids A character vector equal to the number of objects #' provided to append to all cell names; if \code{TRUE}, uses \code{labels} as #' \code{add.cell.ids} #' @param collapse If \code{TRUE}, merge layers of the same name together; if #' \code{FALSE}, appends \code{labels} to the layer name #' #' @return A new v5 assay with data merged from \code{c(x, y)} #' #' @method merge Assay5 #' @export #' #' @family assay5 #' merge.Assay5 <- merge.StdAssay #' @inherit split.Assay5 params return title description details sections #' #' @keywords internal #' @method split StdAssay #' @export #' #' @family stdassay #' split.StdAssay <- function( x, f, drop = FALSE, layers = c("counts", "data"), ret = c('assay', 'multiassays', 'layers'), ... ) { op <- options(Seurat.object.assay.brackets = 'v5') on.exit(expr = options(op)) ret <- ret[1L] ret <- match.arg(arg = ret) layers.to.split <- Layers(object = x, search = layers) if (!identical(Layers(object = x), layers.to.split)) { message( 'Splitting ', paste(sQuote(x = layers.to.split), collapse = ', '), ' layers. Not splitting ', paste( sQuote(x = setdiff(Layers(object = x), layers.to.split)), collapse = ', ' ), '. If you would like to split other layers, set in `layers` argument.' ) } layers <- Layers(object = x, search = layers) layers.split <- list() for (i in seq_along(along.with = layers)) { if (length(x = colnames(x = x[layers[i]])) != length(x = colnames(x = x))) { layers.split[[i]] <- layers[i] } } layers.split <- unlist(x = layers.split) if (length(x = layers.split)) { abort(message = paste( strwrap(x = paste( "The following layers are already split:", paste(sQuote(x = layers.split), collapse = ', '), "\nPlease join before splitting" )) )) } default <- ifelse( test = DefaultLayer(object = x) %in% layers, yes = DefaultLayer(object = x), no = layers[1L] ) cells <- Cells(x = x, layer = layers) if (is_named(x = f)) { f <- f[cells] } if (length(x = f) != length(x = cells)) { abort(message = "Not enough splits for this assay") } if (any(is.na(x = f))) { f <- factor(x = f, levels = c(unique(as.character(f)), 'na')) f[is.na(x = f)] <- 'na' } else { f <- factor(x = f, levels = unique(x = as.character(x = f))) } splits <- split(x = cells, f = f, drop = drop) names(x = splits) <- .MakeNames(x = names(x = splits)) return(switch( EXPR = ret, assay = { for (lyr in layers) { p <- progressor(steps = length(x = splits)) p( message = paste( 'Splitting layer', sQuote(x = lyr), 'into', length(x = splits), 'splits' ), class = 'sticky', amount = 0 ) lcells <- Cells(x = x, layer = lyr) for (i in seq_along(along.with = splits)) { p( message = paste( 'Creating split for', sQuote(x = names(x = splits)[i]) ), class = 'sticky', amount = 0 ) group <- paste(lyr, names(x = splits)[i], sep = '.') xcells <- intersect(x = splits[[i]], y = lcells) LayerData(object = x, layer = group, cells = xcells) <- LayerData( object = x, layer = lyr, cells = xcells ) p() } p(type = 'finish') suppressWarnings(expr = LayerData(object = x, layer = lyr) <- NULL) DefaultLayer(object = x) <- default } x }, multiassays = { value <- vector(mode = 'list', length = length(x = splits)) names(x = value) <- names(x = splits) for (group in names(x = splits)) { value[[group]] <- subset( x = x, cells = splits[[group]], layers = layers ) Key(object = value[[group]]) <- Key(object = group, quiet = TRUE) } value }, layers = { groups <- apply( X = expand.grid(layers, names(x = splits)), MARGIN = 1L, FUN = paste, collapse = '.' ) value <- vector(mode = 'list', length = length(x = groups)) names(x = value) <- groups for (lyr in layers) { lcells <- Cells(x = x, layer = lyr) for (i in seq_along(along.with = splits)) { group <- paste(lyr, names(x = splits)[i], sep = '.') xcells <- intersect(x = splits[[i]], y = lcells) value[[group]] <- LayerData(object = x, layer = lyr, cells = xcells) } } value }, abort(message = paste("Unknown split return type", sQuote(x = ret))) )) } #' Split an Assay #' #' @inheritParams [.Assay5 #' @inheritParams base::split #' @param layers Names of layers to include in the split; pass \code{NA} for #' all layers; pass \code{NULL} for the \link[=DefaultLayer]{default layer} #' @param ret Type of return value; choose from: #' \itemize{ #' \item \dQuote{\code{assay}}: a single \code{\link{Assay5}} object #' \item \dQuote{\code{multiassay}}: a list of \code{\link{Assay5}} objects #' \item \dQuote{\code{layers}}: a list of layer matrices #' } #' @template param-dots-ignored #' #' @return Depends on the value of \code{ret}: #' \itemize{ #' \item \dQuote{\code{assay}}: \code{x} with the layers requested in #' \code{layers} split based on \code{f}; all other layers are left as-is #' \item \dQuote{\code{multiassay}}: a list of \code{\link{Assay5}} objects; #' the list contains one value per split and each assay contains only the #' layers requested in \code{layers} with the \link[=Key]{key} set to the split #' \item \dQuote{\code{layers}}: a list of matrices of length #' \code{length(assays) * length(unique(f))}; the list is named as #' \dQuote{\code{layer.split}} #' } #' #' @method split Assay5 #' @export #' #' @family assay5 #' #' @template section-progressr #' split.Assay5 <- split.StdAssay #' @inherit subset.Assay5 params return title description details sections #' #' @keywords internal #' @method subset StdAssay #' @export #' #' @family stdassay #' subset.StdAssay <- function( x, cells = NULL, features = NULL, layers = NULL, ... ) { if (is.null(x = cells) && is.null(x = features)) { return(x) } # Check the cells vector if (all(is.na(x = cells))) { cells <- Cells(x = x, layer = NA) } else if (any(is.na(x = cells))) { warning( "NAs passed in cells vector, removing NAs", call. = FALSE, immediate. = TRUE ) cells <- cells[!is.na(x = cells)] } if (is.numeric(x = cells)) { cells <- Cells(x = x, layer = NA)[cells] } cells <- intersect(x = Cells(x = x, layer = NA), y = cells) if (!length(x = cells)) { stop("None of the cells provided found in this assay", call. = FALSE) } # Check the features vector if (all(is.na(x = features))) { features <- Features(x = x, layer = NA) } else if (any(is.na(x = features))) { warning( "NAs passed in features vector, removing NAs", call. = FALSE, immediate. = TRUE ) features <- features[!is.na(x = features)] } if (is.numeric(x = features)) { features <- Features(x = x, layer = NA)[features] } features <- intersect(x = features, y = Features(x = x, layer = NA)) if (!length(x = features)) { stop("None of the features provided found in this assay", call. = FALSE) } # Check the layers layers.all <- Layers(object = x) layers <- layers %||% layers.all layers <- match.arg( arg = layers, choices = layers.all, several.ok = TRUE ) # Remove unused layers for (lyr in setdiff(x = layers.all, y = layers)) { LayerData(object = x, layer = lyr) <- NULL } # Perform the subsets for (l in layers) { lcells <- MatchCells( new = Cells(x = x, layer = l), orig = cells, ordered = TRUE ) lfeatures <- MatchCells( new = Features(x = x, layer = l), orig = features, ordered = TRUE ) if (is.null(x = lcells) || is.null(x = features)) { LayerData(object = x, layer = l) <- NULL } else { LayerData(object = x, layer = l) <- LayerData( object = x, layer = l, cells = lcells, features = lfeatures ) } } slot(object = x, name = 'cells') <- droplevels(x = slot( object = x, name = 'cells' )) # Update the cell/feature maps for (i in c('cells', 'features')) { slot(object = x, name = i) <- droplevels(x = slot(object = x, name = i)) } # Subset feature-level metadata mfeatures <- MatchCells( new = Features(x = x, layer = NA), orig = features, ordered = TRUE ) slot(object = x, name = 'meta.data') <- slot( object = x, name = 'meta.data' )[mfeatures, , drop = FALSE] validObject(object = x) return(x) } #' Subset an Assay #' #' @inheritParams [[.Assay5 #' @param cells Cell names #' @param features Feature names #' @param layers Layer to keep; defaults to all layers #' #' @return \code{x} with just the cells and features specified by #' \code{cells} and \code{features} for the layers specified by \code{layers} #' #' @method subset Assay5 #' @export #' #' @family assay5 #' subset.Assay5 <- subset.StdAssay #' @rdname sub-sub-.StdAssay #' #' @method tail StdAssay #' @export #' tail.StdAssay <- tail.Assay #' @return \code{tail}: the last \code{n} rows of feature-level meta data #' #' @rdname sub-sub-.Assay5 #' #' @method tail Assay5 #' @export #' tail.Assay5 <- tail.StdAssay #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Internal #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% .VFLayers <- function( object, type = c('hvf', 'svf'), layers = NA, missing = FALSE ) { type <- type[1L] type <- match.arg(arg = type) pattern <- switch( EXPR = type, 'hvf' = '^vf_', stop("Unknown type: '", type, "'", call. = FALSE) ) vf.cols <- grep( pattern = paste0(pattern, '[[:alnum:]]+_'), x = colnames(x = object[[]]), value = TRUE ) vf.layers <- unique(x = unlist(x = lapply( X = strsplit(x = vf.cols, split = '_'), FUN = function(x) { return(paste(x[3L:(length(x = x) - 1L)], collapse = '_')) } ))) if (!isTRUE(x = missing)) { vf.layers <- intersect( x = vf.layers, y = Layers(object = object, search = layers) ) } if (!length(x = vf.layers)) { vf.layers <- NULL } return(vf.layers) } #' @param object A \code{\link{StdAssay}} object #' @param type Type of variable feature method to pull; choose from: #' \itemize{ #' \item \dQuote{\code{hvf}}: highly variable features #' \item \dQuote{\code{svf}}: spatially variable features #' } #' @param layers Vector of layers to restrict methods for, or a search pattern #' for multiple layers #' #' @return A vector of variable feature methods found in \code{object} #' #' @noRd #' .VFMethods <- function( object, type = c('hvf', 'svf'), layers = NA, missing = FALSE ) { type <- type[1L] type <- match.arg(arg = type) pattern <- switch( EXPR = type, 'hvf' = '^vf_', abort(message = paste("Unknown type:", sQuote(x = type))) ) vf.cols <- grep( pattern = paste0(pattern, '[[:alnum:]]+_'), x = colnames(x = object[[]]), value = TRUE ) # layers <- Layers(object = object, search = layers) layers <- .VFLayers( object = object, type = type, layers = layers, missing = missing ) vf.cols <- Filter( f = function(x) { x <- unlist(x = strsplit(x = x, split = '_')) x <- paste(x[3:(length(x = x) - 1L)], collapse = '_') return(x %in% layers) }, x = vf.cols ) vf.methods <- unique(x = unlist(x = lapply( X = strsplit(x = vf.cols, split = '_'), FUN = '[[', 2L ))) if (!length(x = vf.methods)) { vf.methods <- NULL } return(vf.methods) } #' @param object A \code{\link{StdAssay}} object #' @param type Type of variable feature method to pull; choose from: #' \itemize{ #' \item \dQuote{\code{hvf}}: highly variable features #' \item \dQuote{\code{svf}}: spatially variable features #' } #' @param layers Vector of layers to restrict methods for, or a search pattern #' for multiple layers #' #' @return A vector of variable feature methods and corresponding layers found in \code{object} #' #' @importFrom stats setNames #' @importFrom utils modifyList #' #' @noRd #' .VFMethodsLayers <- function( object, type = c('hvf', 'svf'), layers = NA, missing = FALSE ) { type <- type[1L] type <- match.arg(arg = type) pattern <- switch( EXPR = type, 'hvf' = '^vf_', abort(message = paste("Unknown type:", sQuote(x = type))) ) vf.cols <- grep( pattern = paste0(pattern, '[[:alnum:]]+_'), x = colnames(x = object[[]]), value = TRUE ) # layers <- Layers(object = object, search = layers) layers <- .VFLayers( object = object, type = type, layers = layers, missing = missing ) vf.cols <- Filter( f = function(x) { x <- unlist(x = strsplit(x = x, split = '_')) x <- paste(x[3:(length(x = x) - 1L)], collapse = '_') return(x %in% layers) }, x = vf.cols ) # Extract methods and layers vf.methods.layers <- lapply(vf.cols, function(col) { components <- strsplit(col, split = "_")[[1]] method <- components[2] layer <- paste(components[3:(length(components) - 1)], collapse = "_") return(c(method = method, layer = layer)) }) # Combine into a list vf.list <- lapply(unique(unlist(lapply(vf.methods.layers, `[[`, "method"))), function(method) { layers <- unique(unlist(lapply(vf.methods.layers, function(x) { if (x['method'] == method) return(x['layer']) }))) return(setNames(list(layers), method)) }) vf.list <- Reduce(modifyList, vf.list) if (!length(x = vf.list)) { vf.list <- NULL } return(vf.list) } CalcN5 <- function(object) { if (IsMatrixEmpty(x = LayerData(object = object))) { return(NULL) } return(list( nCount = colSums(x = object), nFeature = colSums(x = LayerData(object = object) > 0) )) } # Join single layers # JoinSingleLayers <- function( object, layers = NULL, new = NULL, default = TRUE, nfeatures = Inf, ... ) { if (is.null(x = layers)) { stop('Layers cannot be NULL') } if (length(x = layers) > 1L) { stop('The length of input layers should be 1') } layers <- Layers(object = object, search = layers) new <- new %||% 'newlayer' if (length(x = layers) == 1L) { LayerData(object = object, layer = new) <- LayerData(object = object, layer = layers) return(object) } if (length(x = layers) == 0L) { return(object) } # Stitch the layers together ldat <- StitchMatrix( x = LayerData(object = object, layer = layers[1L]), y = lapply(X = layers[2:length(x = layers)], FUN = LayerData, object = object), rowmap = slot(object = object, name = 'features')[, layers], colmap = slot(object = object, name = 'cells')[, layers] ) LayerData(object = object, layer = new) <- ldat # Set the new layer as default if (isTRUE(x = default)) { DefaultLayer(object = object) <- new } # Remove the old layers for (lyr in layers) { object[lyr] <- NULL } return(object) } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # S4 methods #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% setAs( from = 'Assay', to = 'Assay5', def = function(from) { # Initialize the new object to <- new( Class = 'Assay5', cells = LogMap(y = colnames(x = from)), features = LogMap(y = rownames(x = from)), assay.orig = DefaultAssay(object = from) %||% character(length = 0L), meta.data = EmptyDF(n = nrow(x = from)), key = Key(object = from) ) # browser() # Add the expression matrices for (i in c('counts', 'data', 'scale.data')) { adata <- GetAssayData(object = from, layer = i) if (IsMatrixEmpty(x = adata)) { next } LayerData(object = to, layer = i) <- adata } # Set the default layer DefaultLayer(object = to) <- ifelse( test = 'counts' %in% Layers(object = to) && !'scale.data' %in% Layers(object = to), yes = 'counts', no = 'data' ) # Add feature-level meta data to[[]] <- from[[]] # Set Variable features VariableFeatures(object = to) <- VariableFeatures(object = from) # Add miscellaneous data mdata <- Misc(object = from) for (i in names(x = mdata)) { Misc(object = to, slot = i) <- mdata[[i]] } return(to) } ) setAs( from = 'Assay5', to = 'Assay', def = function(from) { data.list <- c() original.layers <- Layers(object = from) layers.saved <- c() for (i in c('counts', 'data', 'scale.data')) { layers.saved <- c(layers.saved, Layers(object = from, search = i)) if (length(Layers(object = from, search = i)) > 1) { warning("Joining '", i, "' layers. If you have the same cells in multiple layers, ", "the expression value for the cell in the '", i, "' slot will be the value from the '", Layers(object = from, search = i)[1], "' layer.", call. = FALSE, immediate. = TRUE) from <- JoinLayers(object = from, layers = i, new = i) } if (i == "data") { if (isTRUE(Layers(object = from, search = i) == "scale.data")) { warning("No counts or data slot in object. Setting 'data' slot using", " data from 'scale.data' slot. To recreate 'data' slot, you", " must set and normalize data from a 'counts' slot.", call. = FALSE) } } adata <- LayerData(object = from, layer = i) if(inherits(x = adata, what = "IterableMatrix")) { warning("Converting IterableMatrix to sparse dgCMatrix", call. = FALSE) adata <- as(object = adata, Class = "dgCMatrix") } data.list[[i]] <- adata } if (IsMatrixEmpty(x = data.list[["data"]])){ data.list[["data"]] <- data.list[["counts"]] } if (any(!(original.layers %in% layers.saved))){ layers.remove <- original.layers[!(original.layers %in% layers.saved)] warning("Layers ", paste0(layers.remove, collapse = ', '), " will be removed from the object as v3 assays only support", " 'counts', 'data', or 'scale.data' slots.", call. = FALSE, immediate. = TRUE) } to <- new( Class = 'Assay', counts = data.list[["counts"]], data = data.list[["data"]], scale.data = data.list[["scale.data"]], assay.orig = DefaultAssay(object = from) %||% character(length = 0L), meta.features = data.frame(row.names = rownames(x = data.list[["data"]])), key = Key(object = from) ) # Add feature-level meta data suppressWarnings(to[[]] <- from[[]]) # set variable features VariableFeatures(object = to) <- VariableFeatures(object = from) mdata <- Misc(object = from) for (i in names(x = mdata)) { Misc(object = to, slot = i) <- mdata[[i]] } return(to) } ) #' @rdname sub-.StdAssay #' setMethod( f = '[<-', signature = c(x = 'StdAssay', i = 'character'), definition = function(x, i, ..., value) { LayerData(object = x, layer = i, ...) <- value return(x) } ) #' @param value A matrix-like object to add as a new layer #' #' @return \code{[<-}: \code{x} with layer data \code{value} saved as \code{i} #' #' @rdname sub-.Assay5 #' setMethod( f = '[<-', signature = c(x = 'Assay5', i = 'character'), definition = function(x, i, ..., value) { return(callNextMethod(x = x, i = i, ..., value = value)) } ) #' @rdname sub-sub-.StdAssay #' setMethod( f = '[[<-', signature = c( x = 'StdAssay', i = 'character', j = 'missing', value = 'data.frame' ), definition = function(x, i, ..., value) { if (!length(x = i) && !ncol(x = value)) { return(x) } i <- match.arg(arg = i, choices = colnames(x = value), several.ok = TRUE) names.intersect <- intersect( x = row.names(x = value), y = Features(x = x, layer = NA) ) if (length(x = names.intersect)) { value <- value[names.intersect, , drop = FALSE] } else if (nrow(x = value) == nrow(x = x)) { row.names(x = value) <- Features(x = x, layer = NA) } else { abort(message = "Cannot add more or less meta data without feature names") } for (n in i) { v <- value[[n]] names(x = v) <- row.names(value) x[[n]] <- v } return(x) } ) #' @rdname sub-sub-.StdAssay #' setMethod( f = '[[<-', signature = c( x = 'StdAssay', i = 'missing', j = 'missing', value = 'data.frame' ), definition = function(x, ..., value) { # Allow removing all meta data if (IsMatrixEmpty(x = value)) { x[[names(x = x[[]])]] <- NULL return(x) } if (is.null(names(x = value))) { warn(message = 'colnames of input cannot be NULL') } else { # If no `i` provided, use the column names from value x[[names(x = value)]] <- value } return(x) } ) #' @importFrom methods selectMethod #' #' @rdname sub-sub-.StdAssay #' setMethod( f = '[[<-', signature = c(x = 'StdAssay', i = 'character', j = 'missing', value = 'factor'), definition = function(x, i, ..., value) { f <- slot( object = selectMethod( f = '[[<-', signature = c( x = 'StdAssay', i = 'character', j = 'missing', value = 'vector' ) ), name = '.Data' ) return(f(x = x, i = i, value = value)) } ) #' @rdname sub-sub-.StdAssay #' setMethod( f = '[[<-', signature = c(x = 'StdAssay', i = 'character', j = 'missing', value = 'NULL'), definition = function(x, i, ..., value) { for (name in i) { slot(object = x, name = 'meta.data')[[name]] <- NULL } return(x) } ) #' @rdname sub-sub-.StdAssay #' setMethod( f = '[[<-', signature = c(x = 'StdAssay', i = 'character', j = 'missing', value = 'vector'), definition = function(x, i, ..., value) { # Add multiple bits of metadata if (length(x = i) > 1L) { value <- rep_len(x = value, length.out = length(x = i)) for (idx in seq_along(along.with = i)) { x[[i[idx]]] <- value[[idx]] } } else { # Add a single column of metadata if (is.null(x = names(x = value))) { if (length(x = unique(x = value)) == 1) { value <- rep_len(x = value, length.out = nrow(x = x)) names(x = value) <- Features(x = x, layer = NA) } else { names(x = value) <- value } } names.intersect <- intersect( x = names(x = value), y = Features(x = x, layer = NA) ) if (!length(x = names.intersect)) { abort(message = "No feature overlap between new meta data and assay") } value <- value[names.intersect] df <- EmptyDF(n = nrow(x = x)) rownames(x = df) <- Features(x = x, layer = NA) # df[[i]] <- if (i %in% names(x = x[[]])) { # x[[i]] # } else { # NA # } df[names(x = value), i] <- value if (nrow(x = slot(object = x, name = 'meta.data')) == 0) { slot(object = x, name = 'meta.data') <- EmptyDF(n = nrow(x = x)) } slot(object = x, name = 'meta.data')[, i] <- df[[i]] } validObject(object = x) return(x) } ) #' @rdname sub-sub-.StdAssay #' setMethod( f = '[[<-', signature = c(x = 'StdAssay', i = 'numeric', j = 'missing', value = 'ANY'), definition = function(x, i, ..., value) { if (ncol(x = x[[]])) { i <- colnames(x = x[[]])[as.integer(x = i)] i <- i[!is.na(x = i)] if (length(x = i)) { x[[i]] <- value } } return(x) } ) #' @rdname sub-sub-.StdAssay #' setMethod( f = '[[<-', signature = c(x = 'StdAssay', i = 'missing', j = 'missing', value = 'NULL'), definition = function(x, ..., value) { slot(object = x, name = 'meta.data') <- EmptyDF(n = nrow(x = x)) return(x) } ) #' @param value Feature-level meta data to add #' #' @return \code{[[<-}: \code{x} with \code{value} added as \code{i} #' in feature-level meta data #' #' @rdname sub-sub-.Assay5 #' #' @order 2 #' setMethod( f = '[[<-', signature = c(x = 'Assay5'), definition = function(x, i, ..., value) { return(callNextMethod(x = x, i = i, ..., value = value)) } ) #' V5 Assay Summaries #' #' Summary maths for \code{\link{StdAssay}} Objects #' #' @inheritParams base::colSums #' @param layer Name of layer to run function on #' @template param-dots-ignored #' #' @return The results of the summary math function for the layer specified #' #' @name v5-assay-summaries #' @rdname v5-assay-summaries #' #' @keywords internal #' NULL #' @rdname v5-assay-summaries #' setMethod( f = 'colMeans', signature = c(x = 'StdAssay'), definition = function(x, na.rm = FALSE, dims = 1, layer = NULL, ...) { return(Matrix::colMeans( x = LayerData(object = x, layer = layer), na.rm = na.rm, dims = dims )) } ) #' @rdname v5-assay-summaries #' setMethod( f = 'colSums', signature = c(x = 'StdAssay'), definition = function(x, na.rm = FALSE, dims = 1, layer = NULL, ...) { return(Matrix::colSums( x = LayerData(object = x, layer = layer), na.rm = na.rm, dims = dims )) } ) #' @rdname v5-assay-summaries #' setMethod( f = 'rowMeans', signature = c(x = 'StdAssay'), definition = function(x, na.rm = FALSE, dims = 1, layer = NULL, ...) { return(Matrix::rowMeans( x = LayerData(object = x, layer = layer), na.rm = na.rm, dims = dims )) } ) #' @rdname v5-assay-summaries #' setMethod( f = 'rowSums', signature = c(x = 'StdAssay'), definition = function(x, na.rm = FALSE, dims = 1, layer = NULL, ...) { return(Matrix::rowSums( x = LayerData(object = x, layer = layer), na.rm = na.rm, dims = dims )) } ) #' V5 Assay Overview #' #' Overview of a \code{\link{StdAssay}} object #' #' @param object A v5 Assay #' #' @template return-show #' #' @keywords internal #' #' @family stdassay #' setMethod( f = 'show', signature = 'StdAssay', definition = function(object) { # Basic assay info cat( .AssayClass(object = object), 'data with', nrow(x = object), 'features for', ncol(x = object), 'cells\n' ) # Feature information if (length(x = VariableFeatures(object = object))) { top.ten <- head(x = VariableFeatures(object = object), n = 10L) top <- 'Top' variable <- 'variable' } else { top.ten <- head(x = Features(x = object), n = 10L) top <- 'First' variable <- '' } features <- paste( variable, paste0( ifelse(test = length(x = top.ten) == 1L, yes = 'feature', no = 'features'), ":\n" ) ) features <- gsub(pattern = '^\\s+', replacement = '', x = features) cat( top, length(x = top.ten), features, paste(strwrap(x = paste(top.ten, collapse = ', ')), collapse = '\n'), '\n' ) cat( "Layers:\n", paste(strwrap(x = paste(Layers(object = object), collapse = ', ')), collapse = '\n'), "\n" ) return(invisible(x = NULL)) } ) #' @rdname split.StdAssay #' setMethod( # Because R is stupid f = 'split', signature = c(x = 'StdAssay'), definition = split.StdAssay ) #' V5 Assay Validity #' #' @templateVar cls StdAssay #' @template desc-validity #' #' @section Layer Validation: #' blah #' #' @inheritSection Key-validity Key Validation #' #' @keywords internal #' #' @name StdAssay-validity #' #' @family stdassay #' #' @seealso \code{\link[methods]{validObject}} #' setValidity( Class = 'StdAssay', method = function(object) { if (isFALSE(x = getOption(x = "Seurat.object.validate", default = TRUE))) { warn( message = paste("Not validating", class(x = object)[1L], "objects"), class = 'validationWarning' ) return(TRUE) } valid <- NULL # Check layers dorder <- c( features = .MARGIN(x = object, type = 'features'), cells = .MARGIN(x = object, type = 'cells') ) adims <- dim(x = object) # c(features, cells) if (!IsNamedList(x = slot(object = object, name = 'layers'), pass.zero = TRUE)) { valid <- c(valid, "'layers' must be a named list") } for (layer in Layers(object = object)) { # Reorder dimensions of layer to c(features, cells) ldims <- dim(x = slot(object = object, name = 'layers')[[layer]])[dorder] if (length(x = ldims) != 2L) { valid <- c(valid, "Layers must be two-dimensional objects") break } # Check that we have the correct features and cells for (i in seq.int(from = 1L, to = 2L)) { if (ldims[i] > adims[i]) { valid <- c( valid, paste0( "Layers may not have more ", names(x = dorder)[i], " than present in the assay (offending layer", layer, ")" ) ) } } # Check that we've recorded the cells and features in the maps for (i in c('cells', 'features')) { didx <- c(features = 1L, cells = 2L)[i] if (!layer %in% colnames(x = slot(object = object, name = i))) { valid <- c( valid, paste0( "All layers must have a record in the ", i, " map (offending layer: ", layer, ")" ) ) } else { nmap <- length(x = slot(object = object, name = i)[[layer]]) if (nmap != ldims[didx]) { valid <- c( valid, paste0( "Layers must have the same ", i, " as present in the map (offending layer: ", layer, ")" ) ) } } } } didx <- slot(object = object, name = 'default') if (length(x = didx)) { if (didx < 0 || didx > length(x = Layers(object = object))) { valid <- c( valid, "'default' must be between 0 and the number of layers present" ) } } # TODO: Check variable features # TODO: Check meta features # TODO: Check key # TODO: Check misc return(valid %||% TRUE) } ) #' @inherit StdAssay-validity title details sections #' #' @templateVar cls Assay5 #' @template desc-validity #' #' @name Assay5-validity #' #' @family assay5 #' #' @seealso \code{\link[methods]{validObject}} #' NULL SeuratObject/NEWS.md0000644000176200001440000001035514525215076013755 0ustar liggesusers# SeuratObject 5.0.1 ## Changes: - Update internal calls to `GetAssayData()` to use `layer` instead of `slot` (#160) - Update Matrix version to 1.6-2 (#164) - Change layer-saving in `SaveSeuratRds()` to move all layers instead of just those in `tempdir()` (#169) - Update internal calls to `SetAssayData()` to use `layer` instead of `slot` (#171) - Replace internal calls of `FilterObjects()` to `.FilterObjects()` (#171) # SeuratObject 5.0.0 ## Added - New `Assay5` class with support for layers; layers provide support for: - arbitrary expression matrix names and number - arbitrary expression matrix shape - disk-backed expression matrices - New `$` method for `Assay` and `Assay5` objects to pull expression matrices, replacing informal usage of `@` - New `LayerData()` and `LayerData()<-` functions to replace `GetAssayData()` and `SetAssayData()`, respectively - Support for renaming cells and features with `dimnames()<-` (changing feature names does not apply to v3 `Assay` objects) - New `SaveSeuratRds()` and `LoadSeuratRds()` to save and load `Seurat` objects with disk-backed layers - New `droplevels.LogMap()` to drop unused entries from a `LogMap` - New ability to split (`split()`) and rejoin layers (`JoinLayers()`) within `Assay` and `Assay5` objects based on grouping factor ## Changes - `slot` argument deprecated in all contexts; where applicable, replaced with `layer` argument - `[` for `Assay` and `Assay5` objects take a layer name to pull an expression matrix - option `Seurat.object.assay.brackets` allows restoring v3/v4 behavior of subsetting the main expression matrix (eg. `data`) - Stricter object validation routines at all levels - `PackageCheck()` deprecated in favor of `rlang::check_installed()` - `AttachDeps()` deprecated in favor of using the `Depends` field of `DESCRIPTION` - Subobjects within a `Seurat` object may have subsets of cells present at the object level - Begun replacement of `stop()` and `warning()` with `rlang::abort()` and `rlang::warn()` for easier debugging - Expanded validation and utility of `KeyMixin` objects ## Removed - Unused object constructors (eg. `Assay()`, `Seurat()`) # SeuratObject 4.1.4 ## Changes - Fixes for `CellsByIdentities` (#80) - Remove {rgeos} from Suggests and replace with {sf} due to {rgeos} package retirement - New check for potential binary breaks between dependencies and SeuratObject # SeuratObject 4.1.3 ## Changes - Move {rgeos} to Suggests; segmentation simplification now requires {rgeos} to be installed manually - Move {sp} to Depends ## Added - Add keys to `Assays` and `DimReducs` in `UpdateSeuratObject` when missing # SeuratObject 4.1.2 ## Changed - Bump required Matrix version to >= 1.5.0 # SeuratObject 4.1.1 ## Changed - Update sparse matrix coersions due to Matrix deprecations # SeuratObject 4.1.0 ## Changed - Allow `UpdateSeuratObject` to work when `data` is `NULL` (#38) - Fix superclass issue with R-devel 4.3.x (#42) ## Added - New `FOV`, `Segmentations`, `Centroids`, and `Molecules` classes for imaging-based spatial datasets # SeuratObject 4.0.4 ## Changed - `CreateSeuratObject.Assay` sets Assay key when not present (#29) - Ignore warnings when creating an `Assay` from a data frame (#32) ## Added - New `CheckMatrix` generic for validating expression matrices # SeuratObject 4.0.3 ## Changed - Export utility functions (#22) - Bug fix in names with `Key.Seurat` (#26) - Improved duplicate key checking and resolution # SeuratObject 4.0.2 ## Changed - Provide default option for `Seurat.checkdots` option if option is not set (#16) # SeuratObject 4.0.1 ## Added - `head` and `tail` methods for `Seurat` and `Assay` objects (#5) - New utility functions (#6): - `AttachDeps` to attach required imported dependencies on package attachment - `IsMatrixEmpty` to test if a matrix is empty or not ## Changed - Allow super classes to replace child classes (#1). For example, allows `Assay` objects to replace `Seurat::SCTAssay` or `Signac::ChromatinAssay` objects of the same name - Better support for creating sparse matrices from `data.table`/`tibble` objects (#4) - Improved error messages for clashing object names (#7) - Allow returning a `NULL` if a subset results in zero cells (#9) ## Removed - SCT-specific code (#2) # SeuratObject 4.0.0 - Initial release of SeuratObject SeuratObject/MD50000644000176200001440000003770214525765720013202 0ustar liggesusersf259de05b6088bb7d6eb625ef43a00fe *DESCRIPTION 51a445d321e29ebb29fee2b069584f4b *LICENSE 38a1ec1533cb9623ce0dd3e08e54ad8e *NAMESPACE 9938a2cea8ab3b709e142e52949a4939 *NEWS.md 34df10962de6a9e289b4adad0cf5eaef *R/RcppExports.R 9e8f7bebd623f8c1ad5aaf356fa671bc *R/assay.R e6de1c8945d89bb0013f72b997bb90cb *R/assay5.R f3445afdd73fab75b0bdbee070ec78a0 *R/centroids.R 2c03d1c86e1284ed38bb114fea2faa21 *R/command.R fb8ad1532db9bd7eca87452ed678c606 *R/compliance.R 55fbb8a1de4de27bc7a49e56141cb30a *R/data.R 64dfee3d405039c4b85d3dcd23b698b1 *R/default.R 15f408e9dd4abb2f8f0c3b1bbbf7575f *R/dimreduc.R 16840e39f7f96b1ddad09d8b7df85d5d *R/fov.R 3de60c78199a79fbbc4561c155c9b2fe *R/generics.R f71882fa33101484a69c20ef89040b6e *R/graph.R 58b8af27bef1b9d90d5709917ee214c4 *R/jackstraw.R 6772a8ec660b0a9c2859158e7ff3f87b *R/keymixin.R 9345b163e3146e9b49cd3692686fa902 *R/layers.R 222cd7f08b6db19122478e9b3449a851 *R/logmap.R d525e66963ea78c0c5ba6696f4e51b67 *R/molecules.R 0f139db2cbaa3f733eeedc81534786a2 *R/neighbor.R 1ceecd33ea5c09c30d02aa15c0d51426 *R/segmentation.R e25e4f12ddc588f0277d077ccf81b55b *R/seurat.R be58ca9eef077e177e46994d21be2065 *R/sparse.R e16adcf267105cedfa73532da6ecfd22 *R/spatial.R 5c83718755291ff7a3a01b952db9d35b *R/utils.R 8edff06f008c10cf7074a4e795a26700 *R/zzz.R 199bf667526d02578e7369087a8a69ad *build/SeuratObject.pdf 9f42bfc9e75fd2d26309e6e94e7f666b *build/partial.rdb 674c3364ad5d96d39b25c4cd5b40af1d *data/pbmc_small.rda f9ed0d71ce9f608edf31cc596e158c0c *man/AddMetaData-StdAssay.Rd f010121c9383289cdc4505f3f7c58eaa *man/AddMetaData.Rd 616d3e66ec85872667b668056d0c4378 *man/Assay-class.Rd e4f23362b67a93f15e87fe1de7b66406 *man/Assay-validity.Rd 6a7f2e21971ec5013223f7224498329e *man/Assay5-class.Rd 94bb42ddd8b7e73a8eacf1b41d601144 *man/Assay5-validity.Rd a3b8624fc2eb59997a2b8b606b387521 *man/Assay5T-class.Rd d36c30ccbb0c33e073f94905e56b2ca6 *man/AssayData-StdAssay.Rd 06de3eba0589f9cd88cacd81f679f940 *man/AssayData.Rd 70c614c9e5a38193c1464f01c7e260ac *man/AttachDeps.Rd ee65335c0b739ea9812006076a1d1f1d *man/Boundaries.Rd 7fe1b8b5e4bc9e5f986fabd9b2571465 *man/CastAssay-StdAssay.Rd dca50051ef7bd80d6190958c86e1b378 *man/CastAssay.Rd e8ce966ddbb660b3808dff4bb27f0490 *man/Cells-StdAssay.Rd a662e4a9c33aa736c2fc7e2effccac06 *man/Cells.Rd 3c6674d8cc1ffd49fdd68ea7054dc8b0 *man/CellsByIdentities.Rd 62f8158d220be99ebf294149a990869d *man/CellsByImage.Rd 5002f885a7d02e2e8d5f467ea3ba2641 *man/Centroids-class.Rd 3b6e233fa03fe531940d6a56c47ee3a8 *man/Centroids-methods.Rd b397cd0c29e6f69bf7ed25db340db929 *man/CheckDots.Rd aa780001dc7540239a4c5696163676a0 *man/CheckFeaturesNames.Rd da8078655056e8130c36c9cb7ba29bd1 *man/CheckGC.Rd 6dd14944650da89abd266e80f2ba4359 *man/CheckLayersName.Rd 75c9a6b2472f5fe44852c20e25c57bfb *man/CheckMatrix.Rd ed97979931f325e7d354148937f658b2 *man/ClassKey.Rd 07575870555b49149ac81395bb3bb397 *man/Command.Rd fd47e3d81c1a12c02576753bdc8fb8dc *man/CreateAssay5Object.Rd ac5923f61c65ffd9f9e88b75a7351e97 *man/CreateAssayObject.Rd 056dc3ab9a4117dbcdfc6ccc798066c1 *man/CreateCentroids.Rd 585ae97fde946efd21aef528d28d93bb *man/CreateDimReducObject.Rd 8c292029fd870e06da8474a324b2afed *man/CreateFOV.Rd b02fdbbeec7fa4c3bbe58b5a0ce147aa *man/CreateMolecules.Rd 1916fc94cf53368fa03d7c30c2e26e17 *man/CreateSegmentation.Rd a9186d1a9e9ac0c8f122f33ca510cb21 *man/CreateSeuratObject.Rd c21445135a11a1232e04b19268a13d86 *man/Crop.Rd e287a29557ef3c1fb37d0b50a7b6ce50 *man/DefaultAssay-StdAssay.Rd d68695d6866bd6c4b10db544e2131ca3 *man/DefaultAssay.Rd be193086f8b6b08418051b4b139d12aa *man/DefaultDimReduc.Rd 4030ae62870bab574a9e2021fb85a008 *man/DefaultFOV.Rd 0af832dbabbd34508e6d8dacca8d6254 *man/DefaultLayer-StdAssay.Rd b789aa4ae023bda9750f3c5accd59f7d *man/DefaultLayer.Rd aa35a63f7b32d31f9c5d3ceaa9949c3d *man/DimReduc-class.Rd e622f12c40bf30b466725d31b438c793 *man/DimReduc-validity.Rd 3fbbf118376bc55e71b62459f214a0cb *man/Distances.Rd 2eec1b225da7d23d2ab12169c6da56b5 *man/Embeddings.Rd e5fbe83d0d833d15c572606cdc35d37b *man/EmptyDF.Rd 67b1189672717126cf9b551ddfd59223 *man/ExtractField.Rd 74dd453e1ed49f886b46320373ad324a *man/FOV-class.Rd a1b128afa7f7e191523de1416e578b48 *man/FOV-methods.Rd 557c7ee742562e24c62ccd2893016794 *man/FOV-validity.Rd b492ee39d81ad910010e8ad89d0bd323 *man/FetchData.Rd e59c7577666de2b0ba8735c1dd08bef0 *man/FilterObjects.Rd f5813c66d90e0e41471779f502142a99 *man/GetImage.Rd a8d7f4dcf70294bf8fc450f5ec86b613 *man/GetTissueCoordinates.Rd 64e8bc99510d410cdfa662a7c8ec2f14 *man/Graph-class.Rd fb44cc961ea130ee6f5780cbc528e53e *man/Idents.Rd 8ce644523c9b724668641ec87c8b3ac9 *man/Images.Rd a14301c861b6be050b298a156565f698 *man/Indices.Rd f65a308c6130160a7b0cc71a3e03d6f1 *man/IsGlobal.Rd 20b170c73bfbccb9c4087027a4228aa7 *man/IsMatrixEmpty.Rd 5a95da24e68c27ac6884a73d0140f28a *man/IsNamedList.Rd dc2e97055aa38878e7a3382bac8a67b8 *man/IsSparse.Rd 539bbb8c43d038c789aba294961c08e7 *man/JS.Rd bd0aa85cedf8142d552e748e12beb97f *man/JackStrawData-class.Rd 285b669f3370dcfc2bd9385887084b7a *man/JackStrawData-methods.Rd cfb9746bb898c27360679cba14bb4d4a *man/Key-validity.Rd 8ba6fdea976cb582ae80631848e268c3 *man/Key.Rd 5b431558c51fb98a9a3fa5dc7111c097 *man/KeyMixin-class.Rd 12bbf02149ac2c7cb965ec42b5ddf639 *man/Layers-StdAssay.Rd 8038d4b773d9f261320e8ca747e68d04 *man/Layers.Rd 00fb4ca6f4bc7cfaaf16a70687cac27e *man/Loadings.Rd 057e04725458009e92ea859f97c56a28 *man/LogMap-class.Rd 7f2b9c14ec35d5381db2f6a1dfaff5d4 *man/LogMap-validity.Rd fd6485e90fe15663fa9a4fbab94064aa *man/LogSeuratCommand.Rd 6d87559fa98e7ce67c72077b552c1c53 *man/MatchCells.Rd 493b3581a90f3ba5564a576377971905 *man/Misc-StdAssay.Rd 107fd64783bda998708c1ba49f0a8d10 *man/Misc.Rd a2759f4e73f5642b6730496db3dfa831 *man/Molecules-class.Rd 7104c9867c2aee81bffa674eaf9e7756 *man/Molecules-methods.Rd c573ddfb5d75ed2ecebf11e60b4e7ac0 *man/NNIndex.Rd b69ec370a967359b606c97a746a06136 *man/Neighbor-class.Rd d5d1da2125ae172295b4c596442e728c *man/Neighbor-methods.Rd 77241986bd6e5ca989b2ef8c8499365e *man/ObjectAccess.Rd e8d1ea2158db9906c7c51c9c16d1ef3f *man/Overlay.Rd a3c475f9f8313f74ea2d50f8ebab89cc *man/PackageCheck.Rd f4a54a48c3df0355c6af2c3fa1af0b55 *man/PolyVtx.Rd 2e2aa4b4d568fed8fd2dc69b08877408 *man/Project.Rd 74efaac6adcddf6f1f7c73245978d8b5 *man/Radius.Rd c303c8310c7fa9c675157bfb38bc6d95 *man/RandomName.Rd 4a470abb721f3b5a881d7164f97411ad *man/RegisterSparseMatrix.Rd 8b21888ce66474589a1b5df6aa89e2f1 *man/RenameAssays.Rd ef685e9a797bab755448f1a9ca14e927 *man/RenameCells-StdAssay.Rd 9fbe83085937d7ce30a05341aae7f8a1 *man/RenameCells.Rd 3cccbc7351846becfa577101424b2551 *man/RowMergeSparseMatrices.Rd 5a2e6e92b3a30f36b712c12184a67fcb *man/SaveSeuratRds.Rd cb3225f30e5114a4cd5d8e6fc573df8e *man/Segmentation-class.Rd 12d453eb170bea9c910479816839d61c *man/Segmentation-methods.Rd 55efcf9cd70c264f01708e465ccf28fa *man/Seurat-class.Rd dbce0e6488e46310242a5cdcfd96cc99 *man/Seurat-validity.Rd 2f9f2aab7b8e18af0d49273ab9ae3ef6 *man/SeuratCommand-class.Rd 668237c345344d6bf0bc122117a7e51d *man/SeuratObject-options.Rd 64e2974ae0f8894233c37ae7edfa4d70 *man/SeuratObject-package.Rd ec4884e558a673afcd11b4de8081fea4 *man/Simplify.Rd 549d0dfd91fccdfbb07935c645c4c595 *man/SparseEmptyMatrix.Rd 13eabbc40ce41e7282871bff4a6ed602 *man/SpatialImage-class.Rd 5771c9674754f5c9aee5b5f1a2a3f6cc *man/SpatialImage-methods.Rd da2e9b7ebbdb5350fc81511755750523 *man/SplitLayers.Rd b539da26d03e26fac6da93c138b1eeed *man/StdAssay-class.Rd 0bb7de412093650876711112aadc5e13 *man/StdAssay-validity.Rd 36d940b4f7071a8c84f5c9c5868a7eb7 *man/Stdev.Rd 40a8e43e919b49981034125ab04ee41f *man/StitchMatrix.Rd 53168ebb6c392d96cc16711313f62a93 *man/Theta.Rd ae755af60f7f03f074fd930b6505dc86 *man/Tool.Rd 2fca52f2ce5f3d6f20522c0ffe259462 *man/UpdateSeuratObject.Rd ef2a5ebda0c98dc158c2c55b98da3348 *man/UpdateSlots.Rd a689d1b130522c1c485a0d8cde91b944 *man/VariableFeatures-StdAssay.Rd f5f70765151d255f9a5f760600de320b *man/VariableFeatures.Rd 3ba1e2ae496857d51b279a466818b94e *man/Version.Rd 166350b457da176818d2e6a24d9352e5 *man/WhichCells.Rd 2dd900aec96dd7df50d9c530057031df *man/aggregate.Rd 407940b34bdc1c5653d793b1ae8dba30 *man/angles.Rd 933a4f7cbb83a4975bd64ed502c91355 *man/as.Centroids.Rd 18ebaaaf29f17b0b62ee0494cabfb0a8 *man/as.Graph.Rd 764355bf04b972b2cc848e22836ddb49 *man/as.Neighbor.Rd a9b6c9eacfbf9b0f9daef9ee280a0716 *man/as.Seurat.Rd c88b9218ac568bed06e3aaf7e593a0a5 *man/as.list.SeuratCommand.Rd e44f1daa080357a472b98dccc9c6bafe *man/as.matrix.LogMap.Rd 060d10cdca1afd48541066dc38c90368 *man/as.sparse.Rd 441d5b687d3d5e36c49c9a68bd4cabf6 *man/cash-.Assay.Rd 2c86cea8dd94aef26ecedbd8b34142a5 *man/cash-.Assay5.Rd 5e866a9b43051e9c16fcb426a2fe10b6 *man/cash-.Seurat.Rd 0b582389d325c009a7b1342ef7038f45 *man/cash-.SeuratCommand.Rd 85fdda36b4fc72762498957da37f7943 *man/cash-.StdAssay.Rd 5b9e319f90cf8477a16783b225440ebe *man/colMeans-Assay-method.Rd fd6dd58ec58f373e3f9107215d969174 *man/colMeans-Seurat-method.Rd 76a93b933e50e3fcdaaf4085a2a078fe *man/dim.Assay.Rd 0dd27e8b9af778181951587c60092b93 *man/dim.Assay5.Rd 61b93e58d2eb90a04b19aea1501b5430 *man/dim.DimReduc.Rd e50731bd318b4802a7eb30f2d0214407 *man/dim.Seurat.Rd edf104f32e5346ad6cd66ed5241196d1 *man/dim.StdAssay.Rd ea06feef772b4f8d54fadc40147e89ef *man/dimnames.Assay.Rd abe8607dd72d43d40e8bf456b96ea4d6 *man/dimnames.Assay5.Rd 5c5289d0932120ba5a81ae0cb5da7031 *man/dimnames.Seurat.Rd 2f123a04259af7a0a11c866f3d8e17e7 *man/dimnames.StdAssay.Rd 979af8e581327f11d3327bb00f8a51ff *man/dot-AssayClass.Rd 59dbfdd330fe37c358f4fb8bfd8a69fb *man/dot-BPMatrixMode.Rd 82986e08688df33e48833cd820edc1b9 *man/dot-CalcN.Rd 81a9cd78a67f899e434aa1e0a1879ed0 *man/dot-CheckFmargin.Rd c2cd9ec42f5ced7b709a906ad7ec0f6d *man/dot-ClassPkg.Rd e9433bd26caaff53dbf128bc379cd27f *man/dot-Collections.Rd 55f6ca223340aae1e82f1da1c315d652 *man/dot-Contains.Rd 10e6da96166a77f331faf9cbeaf1268a *man/dot-CreateStdAssay.Rd 0b3a18a4dc4cca432b8eba84db8b3b3a *man/dot-DefaultFOV.Rd 280c7b2edff3c4e44c46dafd8938be8d *man/dot-Deprecate.Rd ec08ddf520e35603d88f52b500dd7dc7 *man/dot-DiskLoad.Rd 454b7cc84209edc6c18f257e31152db3 *man/dot-DollarNames.Assay.Rd a8bdfbd37fa2e4899140f2e3d17170fa *man/dot-DollarNames.Assay5.Rd 28e60dd90bbd2cbd409add8a8cb4355e *man/dot-DollarNames.Seurat.Rd b50119132bccbc83385fcbe0ae1e6d35 *man/dot-DollarNames.SeuratCommand.Rd e1e95c5cf1badf20f3710b2c30938e3e *man/dot-DollarNames.StdAssay.Rd 179a72f565ab967f0af409fe7fc7a363 *man/dot-FileMove.Rd 774133c2529873d49b4cfeaa14309263 *man/dot-FilePath.Rd 5a53290427b7d4f1b40a815bd5df9930 *man/dot-FilterObjects.Rd d76a803f1a36d6593ea1d934130b4e39 *man/dot-FindObject.Rd fe071100b7662afbbed2e67c6d30bb2b *man/dot-GetMethod.Rd 0ad6bf6483cbbf1d657b2c4b392138fb *man/dot-IsFutureSeurat.Rd d0cea3ab20c3d95e25e108dc12b68cbb *man/dot-KeyPattern.Rd 86e943e5db8af1862b22c88961bfd7fc *man/dot-MARGIN.Rd 28b9b58c10823c25567e61474eeb2dd7 *man/dot-PropagateList.Rd 076af451d3492abb6a10af41afb6d13a *man/dot-RandomKey.Rd 4b545cd03c78def67bbe861848b4838b *man/dot-SelectFeatures.Rd aafcbb1daaa1d99fbcbf28fe7a289a94 *man/dot-SparseSlots.Rd c38ea05d4003aa5474867d0a46b8006c *man/dot-Subobjects.Rd d710723273ad7e8b4b80bc5f1d84d4dd *man/droplevels.LogMap.Rd cb1e46f469cfbbbde29c8b5113e1d789 *man/figures/lifecycle-archived.svg c0d2e5a54f1fa4ff02bf9533079dd1f7 *man/figures/lifecycle-defunct.svg a1b8c987c676c16af790f563f96cbb1f *man/figures/lifecycle-deprecated.svg c3978703d8f40f2679795335715e98f4 *man/figures/lifecycle-experimental.svg 952b59dc07b171b97d5d982924244f61 *man/figures/lifecycle-maturing.svg 27b879bf3677ea76e3991d56ab324081 *man/figures/lifecycle-questioning.svg 53b3f893324260b737b3c46ed2a0e643 *man/figures/lifecycle-stable.svg 1c1fe7a759b86dc6dbcbe7797ab8246c *man/figures/lifecycle-superseded.svg f8730a8d7164773ddaf22841f44bb266 *man/intersect.LogMap.Rd c78e7a8079d7ca25b55fbf56de4e72a1 *man/labels.LogMap.Rd 43343e5c36062085e258077a5f8a6294 *man/merge.Assay.Rd debf4b7094b712dc2cf790a6cc84ed17 *man/merge.Assay5.Rd 40a4085fa032570bbf7b134c884c6de9 *man/merge.DimReduc.Rd 884067d93ce6c3d0d7c5ed099227a7b1 *man/merge.Seurat.Rd 31aa7c7ec61a601360ad15da400f495e *man/merge.StdAssay.Rd 6701d529f2a1a6387eabea552915c68a *man/names.Seurat.Rd 1804e7cce177bff73333318c8f29cefb *man/old-assign.Rd 4846f0d21ea2a28c6096147d3ee517cc *man/oldseurat-class.Rd 72ff61f578b283267cf20e05f63293bd *man/pbmc_small.Rd 67e73eb537b9589f7db75d64b9d61e23 *man/print.DimReduc.Rd 174a22404b1c8b6e52c1fef014fc3cb7 *man/reexports.Rd 52b7b8b1fdf300fcfc3358933816899d *man/roxygen/meta.R 9948a98b4cf02f0023d963a6822ebc69 *man/roxygen/templates/desc-validity.R f8f8b7c72db894997c4c699a02891178 *man/roxygen/templates/lifecycle-deprecated.R ef3b2dc2cab64559e290df00aa7aece5 *man/roxygen/templates/lifecycle-experimental.R d72b4995266f56f576e728db07329ada *man/roxygen/templates/lifecycle-superseded.R dc7c0b2012073d518fb7e29829542006 *man/roxygen/templates/method-cells.R 861b2bdb816340853477cc9183549537 *man/roxygen/templates/method-features.R 926283891c3040d113feb2ba4e0166e8 *man/roxygen/templates/method-lengths.R f5501d158cc0717e81b9eef208fbd262 *man/roxygen/templates/method-show.R 7af52116e9baf2f1b960769e5c696545 *man/roxygen/templates/method-stdassay.R 8afd9aa06afa62ae7bf043e3a97915f6 *man/roxygen/templates/name-oldv.R 24034598a79b8f1461b1647f2ce82b3b *man/roxygen/templates/note-reqdpkg.R 47d96c85155d705c5782b78087dafe8e *man/roxygen/templates/param-dots-ignored.R 3b09153b5a6e4c24dcfa2d28a8da93dd *man/roxygen/templates/param-dots-method.R 674e3ec32a1eb9c0f84994fd6a7af746 *man/roxygen/templates/param-verbose.R 6e16a5460e9e990875eea028d2ef7bba *man/roxygen/templates/return-null.R f4e31c6d34d49a994f13999c1b301f51 *man/roxygen/templates/return-show.R 84d7260dd254c3dbeff57c77049aa163 *man/roxygen/templates/section-future.R 19902d3a32e10d5c456ad83cca0e6e57 *man/roxygen/templates/section-progressr.R c734e303b87cac72c78065f539f8c63c *man/roxygen/templates/seealso-methods.R 8b421a0430da79f3617d77d3d4206e40 *man/roxygen/templates/slot-key.R ce42fd10066a88edebd9b93b6c226731 *man/roxygen/templates/slot-misc.R 83845165946a2ec8a088516bd33f1fc9 *man/roxygen/templates/slot-stdassay.R f0281c9d04013fce7ee88878f720c794 *man/s4list.Rd 9725945b96056d0d581f1d7a6dc100b5 *man/set-if-na.Rd 2ba6c2705198b2a2e8b2175a473033e2 *man/set-if-null.Rd e619be82b82abdc58fa8f42b85aa4cd2 *man/show-Assay-method.Rd 6b3ba95b250573707792bec371446831 *man/show-DimReduc-method.Rd 61ff7a13e1a83819ce0f69e25ff9b547 *man/show-Graph-method.Rd a904dbf6ea73840de5eee2837a7c62c7 *man/show-LogMap-method.Rd b0834ed09fc9de9b75285cd798ab855e *man/show-Seurat-method.Rd afbdde96a15e97e09c1c3703ff9384bd *man/show-SeuratCommand-method.Rd 3150b8db98758cf2d96539ce21bbd216 *man/show-StdAssay-method.Rd 51dc3936ecc37d5b1ad56a6312a3b3df *man/show-oldseurat-method.Rd 9cbac366b52fc6f958ba8a8a994e33f7 *man/split.Assay.Rd 32da274c752da40fde945b0c83dfbd46 *man/split.Assay5.Rd bd8415a88519e9c44d14133770f43e10 *man/split.Seurat.Rd 250adb13f339b54ef79a87043cd8bc3c *man/split.StdAssay.Rd 222260b09d633356c6822bf8f8273699 *man/sub-.Assay.Rd c8b569caae955d33492cb6405bed2c37 *man/sub-.Assay5.Rd dc17cea39248d99937dcbe74907d7d69 *man/sub-.DimReduc.Rd 40e9951309f5db2e4a8c58434ced37bf *man/sub-.SeuratCommand.Rd 2fd1adc5f70b7c9c182f5c41ec106f3f *man/sub-.StdAssay.Rd 14396e99fb2f9ad403b1913bc17c6af4 *man/sub-LogMap-method.Rd c1a82d4f5b7dce092c9a8eb6c484dc2d *man/sub-sub-.Assay.Rd 2e5e72c9692d8f987e0f103a77d2f86f *man/sub-sub-.Assay5.Rd c6dfd01f80348d992ead171e20294599 *man/sub-sub-.DimReduc.Rd 1d4480d30dee94bf9753aceb8a0c307f *man/sub-sub-.Seurat.Rd 479257b9d8a58b92e13465b797fec778 *man/sub-sub-.StdAssay.Rd b66ee93ac46276cac312d6f69425058a *man/sub-sub-LogMap-internal-method.Rd 4620fad550fb8f3560bc611db7399032 *man/sub-subset-Seurat-NULL.Rd 6478f71545eb0ebb3c7d3be0ad572dd7 *man/sub-subset-Seurat-character-missing-StdAssay-method.Rd edb7cc5ba86e313828f37b9a5603e2e1 *man/sub-subset-Seurat.Rd 37c1fbb29b83b45b1ee2fcce83d01c2e *man/subset.Assay.Rd cfadfd6154a2169d43a6c04bd104b15f *man/subset.Assay5.Rd b5a3a276793423cab4d4c459d9d125ed *man/subset.DimReduc.Rd 57cb4fff29b0f7c59f6e8e12221daf7d *man/subset.Seurat.Rd 496af400c5f7a40d274319734a320322 *man/subset.StdAssay.Rd b0d3db52c8ee7dcd38760763a5f6dcf0 *man/v5-assay-summaries.Rd 48564b53bdf7cadfa2a1cf088e08fa1a *src/RcppExports.cpp 288fcd4e7664587a425de78708c7f251 *src/data_manipulation.cpp f99ccc0ef8d6bb241950e293d697668f *src/data_manipulation.h f33c09d14c160d9f29a89251fd91a036 *src/valid_pointer.c