SeuratObject/0000755000176200001440000000000014616700266012654 5ustar liggesusersSeuratObject/NAMESPACE0000644000176200001440000004220014616441763014075 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(EmptyMatrix) 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(t) 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(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/LICENSE0000644000176200001440000000006414616441763013665 0ustar liggesusersYEAR: 2021 COPYRIGHT HOLDER: SeuratObject authors SeuratObject/data/0000755000176200001440000000000014616441763013571 5ustar liggesusersSeuratObject/data/pbmc_small.rda0000644000176200001440000016720014616441763016400 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.Rd0000644000176200001440000000134114616441764016315 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.Rd0000644000176200001440000000055314616441763015154 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.Rd0000644000176200001440000000136214616441764015642 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.Rd0000644000176200001440000000136014616441764017001 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.Rd0000644000176200001440000000207314616441764016261 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.Rd0000644000176200001440000000234614616441764015355 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)) 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.Rd0000644000176200001440000000321014616441763016101 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.Rd0000644000176200001440000000070214616441763016717 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.Rd0000644000176200001440000000622214616441764017443 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.Rd0000644000176200001440000000152714616441763017306 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.Rd0000644000176200001440000000172414616441764016400 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.Rd0000644000176200001440000000552214616441764016407 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.Rd0000644000176200001440000000247014616441763014767 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.Assay}()}, \code{\link{dimnames.Assay5}()}, \code{\link{dimnames.Seurat}()} } \concept{data-access} \concept{dimnames} SeuratObject/man/sub-subset-Seurat.Rd0000644000176200001440000000453314616441764017265 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.Rd0000644000176200001440000000172414616441764016103 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.Rd0000644000176200001440000000146514616441764015525 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.Rd0000644000176200001440000000162714616441763015750 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.Rd0000644000176200001440000000122714616441764016351 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.Rd0000644000176200001440000000116614616441764017773 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.Rd0000644000176200001440000000161114616441764017126 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.Rd0000644000176200001440000000153614616441764017717 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.Rd0000644000176200001440000000346714616441764016504 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}}, \code{\link{[[<-,Seurat,NULL}}, \code{\link{dim.Seurat}()}, \code{\link{dimnames.Seurat}()}, \code{\link{merge.Seurat}()}, \code{\link{names.Seurat}()} } \concept{seurat} SeuratObject/man/merge.DimReduc.Rd0000644000176200001440000000210614616441764016514 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.Rd0000644000176200001440000000142114616441764017000 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.Rd0000644000176200001440000000457314616441764016302 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}}, \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/sub-sub-.StdAssay.Rd0000644000176200001440000000445214616441764017117 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.Rd0000644000176200001440000000315314616441764016137 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.Rd0000644000176200001440000000574714616441764016237 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.Rd0000644000176200001440000000567214616441764016217 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.Rd0000644000176200001440000000274214616441763016020 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.Rd0000644000176200001440000000160314616441764014626 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.Rd0000644000176200001440000000067214616441764017427 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.Rd0000644000176200001440000000112014616441764016372 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.Rd0000644000176200001440000000127314616441764021553 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.Rd0000644000176200001440000000506514616441764017036 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.Rd0000644000176200001440000000240414616441763016015 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.Rd0000644000176200001440000000134514616441764017507 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.Rd0000644000176200001440000000207314616441763017344 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.Rd0000644000176200001440000000216114616441764017053 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.Rd0000644000176200001440000000146114616441764017123 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.Rd0000644000176200001440000000214114616441764016723 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.Rd0000644000176200001440000000075614616441764020171 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.Rd0000644000176200001440000000144314616441763015617 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.Rd0000644000176200001440000000113714616441764016371 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.Rd0000644000176200001440000000070014616441764017215 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/EmptyMatrix.Rd0000644000176200001440000000265514616441764016216 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{EmptyMatrix} \alias{EmptyMatrix} \title{Empty Matrices} \usage{ EmptyMatrix(repr = "C", type = "d") } \arguments{ \item{repr}{Representation of empty matrix; choose from: \itemize{ \item \dQuote{\code{C}} for a \code{\link[Matrix:CsparseMatrix-class]{CsparseMatrix}} \item \dQuote{\code{T}} for a \code{\link[Matrix:TsparseMatrix-class]{TsparseMatrix}} \item \dQuote{\code{R}} for an \code{\link[Matrix:RsparseMatrix-class]{RsparseMatrix}} \item \dQuote{\code{e}} for an \code{\link[Matrix:unpackedMatrix-class]{unpackedMatrix}} \item \dQuote{\code{d}} for a dense S3 \code{\link[base]{matrix}} \item \dQuote{\code{spam}} for a \code{\link[spam]{spam}} matrix }} \item{type}{Type of resulting matrix to return, choose from: \itemize{ \item \dQuote{\code{d}} for numeric matrices \item \dQuote{\code{l}} for logical matrices \item \dQuote{\code{n}} for pattern matrices } Note, when \code{repr} is \dQuote{\code{spam}}, \code{type} must be \dQuote{\code{d}}; when \code{repr} is \dQuote{\code{d}}, setting \code{type} to \dQuote{\code{n}} returns a logical matrix} } \value{ A 0x0 matrix of the specified representation and type } \description{ Create empty 0x0 matrices of varying types } \examples{ EmptyMatrix() EmptyMatrix("spam") } \seealso{ \code{\link{IsMatrixEmpty}()} } \concept{utils} SeuratObject/man/ExtractField.Rd0000644000176200001440000000142214616441764016300 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.Rd0000644000176200001440000000300214616441764020013 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.Rd0000644000176200001440000000167414616441764015427 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.Rd0000644000176200001440000000137714616441764017656 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.Rd0000644000176200001440000000202614616441764016215 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.Rd0000644000176200001440000000530214616441764015162 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.Rd0000644000176200001440000000246014616441764020032 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.Rd0000644000176200001440000000116214616441764020052 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.Rd0000644000176200001440000000233714616441764015373 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.Rd0000644000176200001440000000324414616441764016172 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.Rd0000644000176200001440000000272414616441764017403 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/0000755000176200001440000000000014616441764015127 5ustar liggesusersSeuratObject/man/roxygen/templates/0000755000176200001440000000000014616441764017125 5ustar liggesusersSeuratObject/man/roxygen/templates/section-progressr.R0000644000176200001440000000105714616441764022743 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.R0000644000176200001440000000030614616441764022171 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.R0000644000176200001440000000017114616441764021505 0ustar liggesusers#' @details \code{show}: Display an object summary to stdout #' #' @return \code{show}: Invisibly returns \code{NULL} SeuratObject/man/roxygen/templates/slot-key.R0000644000176200001440000000037614616441764021025 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.R0000644000176200001440000000011114616441764022335 0ustar liggesusers#' @seealso \code{<%= cls %>} methods: \code{\link{<%= cls %>-methods}} SeuratObject/man/roxygen/templates/lifecycle-superseded.R0000644000176200001440000000013714616441764023351 0ustar liggesusers#' @section Lifecycle: #' #' \Sexpr[stage=build,results=rd]{lifecycle::badge("superseded")} SeuratObject/man/roxygen/templates/param-verbose.R0000644000176200001440000000005114616441764022007 0ustar liggesusers#' @param verbose Show progress updates SeuratObject/man/roxygen/templates/desc-validity.R0000644000176200001440000000015614616441764022013 0ustar liggesusers#' @description Validation of \code{<%= cls %>} objects is handled by #' \code{\link[methods]{validObject}} SeuratObject/man/roxygen/templates/param-dots-method.R0000644000176200001440000000006114616441764022572 0ustar liggesusers#' @param ... Arguments passed to other methods SeuratObject/man/roxygen/templates/param-dots-ignored.R0000644000176200001440000000002714616441764022743 0ustar liggesusers#' @param ... Ignored SeuratObject/man/roxygen/templates/method-features.R0000644000176200001440000000032114616441764022340 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.R0000644000176200001440000000031714616441764022362 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.R0000644000176200001440000000021414616441764021645 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.R0000644000176200001440000000044314616441764023306 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.R0000644000176200001440000000233314616441764022063 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.R0000644000176200001440000000013714616441764021631 0ustar liggesusers#' @details \code{Cells}: Get cell names #' #' @return \code{Cells}: A vector of cell names SeuratObject/man/roxygen/templates/return-show.R0000644000176200001440000000013714616441764021546 0ustar liggesusers#' @return Prints summary to \code{\link[base]{stdout}} and invisibly #' returns \code{NULL} SeuratObject/man/roxygen/templates/lifecycle-experimental.R0000644000176200001440000000031714616441764023703 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.R0000644000176200001440000000007714616441764021166 0ustar liggesusers#' @slot misc A named list of unstructured miscellaneous data SeuratObject/man/roxygen/templates/section-future.R0000644000176200001440000000134414616441764022226 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.R0000644000176200001440000000005214616441764021534 0ustar liggesusers#' @return Invisibly returns \code{NULL} SeuratObject/man/roxygen/templates/name-oldv.R0000644000176200001440000000050114616441764021126 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.R0000644000176200001440000000131514616441764016200 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.Rd0000644000176200001440000000224114616441763016756 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.Rd0000644000176200001440000000215214616441764015735 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.Rd0000644000176200001440000000402014616441764017143 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}{relevant 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.Rd0000644000176200001440000000254014616441764014617 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.Rd0000644000176200001440000000727214616441764015161 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.Rd0000644000176200001440000000111414616441764015125 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.Rd0000644000176200001440000000126414616441764020040 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.Rd0000644000176200001440000000117414616441764020057 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.Rd0000644000176200001440000000175314616441764017374 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.Rd0000644000176200001440000000104214616441764016057 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.Rd0000644000176200001440000000410214616441764016112 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.Rd0000644000176200001440000000173114616441764020043 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.Rd0000644000176200001440000000063714616441763017430 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.Rd0000644000176200001440000001113614616441764017151 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.Rd0000644000176200001440000000154514616441764015015 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.Rd0000644000176200001440000000170514616441763017547 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.Rd0000644000176200001440000000175014616441764017573 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.Rd0000644000176200001440000000303214616441764016561 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{...}{Ignored} \item{quiet}{Suppress warnings when updating characters to keys} \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.Rd0000644000176200001440000000145714616441764017341 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.Rd0000644000176200001440000000117114616441764020152 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.Rd0000644000176200001440000000125514616441764015334 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.Rd0000644000176200001440000000107514616441764016072 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.Rd0000644000176200001440000000147314616441764016776 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.Rd0000644000176200001440000000127014616441764017011 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}}, \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/JS.Rd0000644000176200001440000000204614616441764014241 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.Rd0000644000176200001440000000204114616441764016265 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}}, \code{\link{[[<-,Seurat,NULL}}, \code{\link{dim.Seurat}()}, \code{\link{dimnames.Seurat}()}, \code{\link{merge.Seurat}()}, \code{\link{subset.Seurat}()} } \concept{seurat} SeuratObject/man/dot-CreateStdAssay.Rd0000644000176200001440000000510614616441764017370 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.Rd0000644000176200001440000000231614616441763016714 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{nchar() == 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.Rd0000644000176200001440000000126714616441763015446 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.Rd0000644000176200001440000000277614616441764020063 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.Rd0000644000176200001440000000226114616441764016553 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.Rd0000644000176200001440000000074314616441764015473 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.Rd0000644000176200001440000000174214616441764016313 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.Rd0000644000176200001440000000204614616441764017443 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.Rd0000644000176200001440000000511014616441764016556 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.Rd0000644000176200001440000000152414616441764016230 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/0000755000176200001440000000000014616441764015100 5ustar liggesusersSeuratObject/man/figures/lifecycle-defunct.svg0000644000176200001440000000170414616441764021210 0ustar liggesuserslifecyclelifecycledefunctdefunct SeuratObject/man/figures/lifecycle-maturing.svg0000644000176200001440000000170614616441764021410 0ustar liggesuserslifecyclelifecyclematuringmaturing SeuratObject/man/figures/lifecycle-archived.svg0000644000176200001440000000170714616441764021350 0ustar liggesusers lifecyclelifecyclearchivedarchived SeuratObject/man/figures/lifecycle-questioning.svg0000644000176200001440000000171414616441764022126 0ustar liggesuserslifecyclelifecyclequestioningquestioning SeuratObject/man/figures/lifecycle-superseded.svg0000644000176200001440000000171314616441764021723 0ustar liggesusers lifecyclelifecyclesupersededsuperseded SeuratObject/man/figures/lifecycle-stable.svg0000644000176200001440000000167414616441764021040 0ustar liggesuserslifecyclelifecyclestablestable SeuratObject/man/figures/lifecycle-experimental.svg0000644000176200001440000000171614616441764022260 0ustar liggesuserslifecyclelifecycleexperimentalexperimental SeuratObject/man/figures/lifecycle-deprecated.svg0000644000176200001440000000171214616441764021657 0ustar liggesuserslifecyclelifecycledeprecateddeprecated SeuratObject/man/sub-.Assay.Rd0000644000176200001440000000253014616441764015650 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.Rd0000644000176200001440000000063014616441764016177 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.Rd0000644000176200001440000000177714616441764016464 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.Rd0000644000176200001440000000155714616441764015773 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.Rd0000644000176200001440000000320414616441764015343 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.Rd0000644000176200001440000000115614616441764015761 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.Rd0000644000176200001440000000125414616441764017462 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.Rd0000644000176200001440000000233714616441764016671 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.Rd0000644000176200001440000000105514616441764017654 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.Rd0000644000176200001440000000754614616441764016472 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.Rd0000644000176200001440000000071714616441764015355 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.Rd0000644000176200001440000000250514616441764016266 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.Rd0000644000176200001440000000152514616441764016307 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.Rd0000644000176200001440000000271214616441764015465 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.Rd0000644000176200001440000000361414616441764016314 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.Rd0000644000176200001440000000055514616441764015471 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.Rd0000644000176200001440000000142414616441764016766 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.Rd0000644000176200001440000000147614616441764015563 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.Rd0000644000176200001440000000077114616441764020726 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.Rd0000644000176200001440000000147214616441764016522 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.Rd0000644000176200001440000000143014616441764016174 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.Rd0000644000176200001440000000070414616441764016266 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.Rd0000644000176200001440000000225414616441764016557 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.Rd0000644000176200001440000000233314616441764016035 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.Rd0000644000176200001440000000334114616441764016523 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.Rd0000644000176200001440000001327214616441764016023 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.Rd0000644000176200001440000000300214616441763016620 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{nchar() == 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.Rd0000644000176200001440000000042614616441764014772 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.Rd0000644000176200001440000000701114616441763017314 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.Rd0000644000176200001440000000344214616441764017261 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.Rd0000644000176200001440000000200714616441764016776 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.Rd0000644000176200001440000000175014616441764015665 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.Rd0000644000176200001440000000642114616441764016267 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}}, \code{\link{[[<-,Seurat,NULL}}, \code{\link{dim.Seurat}()}, \code{\link{dimnames.Seurat}()}, \code{\link{names.Seurat}()}, \code{\link{subset.Seurat}()} } \concept{seurat} SeuratObject/man/Key.Rd0000644000176200001440000000304314616441764014453 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.Rd0000644000176200001440000000113314616441764015172 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.Rd0000644000176200001440000000116714616441764020325 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.Rd0000644000176200001440000000075514616441764015242 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.Rd0000644000176200001440000000246014616441764017303 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{nchar() == 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.Rd0000644000176200001440000000104214616441764017422 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.Rd0000644000176200001440000000153014616441764016562 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.Rd0000644000176200001440000000551314616441764017712 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://satijalab.github.io/seurat-object/} \item \url{https://github.com/satijalab/seurat-object} \item Report bugs at \url{https://github.com/satijalab/seurat-object/issues} } } \author{ \strong{Maintainer}: Rahul Satija \email{seurat@nygenome.org} (\href{https://orcid.org/0000-0001-9448-8833}{ORCID}) Authors: \itemize{ \item Paul Hoffman \email{hoff0792@alumni.umn.edu} (\href{https://orcid.org/0000-0002-7693-8957}{ORCID}) \item David Collins \email{dcollins@nygenome.org} (\href{https://orcid.org/0000-0001-9243-7821}{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.Rd0000644000176200001440000000301614616441764025670 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.Rd0000644000176200001440000000355514616441764016723 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.Rd0000644000176200001440000000637514616441764016623 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.Rd0000644000176200001440000000334314616441764015551 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.Rd0000644000176200001440000000412014616441764016155 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}}, \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/DefaultAssay-StdAssay.Rd0000644000176200001440000000126414616441764020044 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.Rd0000644000176200001440000000227314616441763016130 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.Rd0000644000176200001440000000153714616441764016470 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.Rd0000644000176200001440000000105514616441764017464 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.Rd0000644000176200001440000000150214616441764015740 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.Rd0000644000176200001440000000240114616441764017247 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.Rd0000644000176200001440000000155014616441764017261 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}}, \code{\link{LogMap-validity}}, \code{\link{as.matrix.LogMap}()}, \code{\link{intersect.LogMap}()}, \code{\link{labels.LogMap}()} } \concept{logmap} SeuratObject/man/NNIndex.Rd0000644000176200001440000000132514616441764015227 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.Rd0000644000176200001440000000172614616441764016261 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.Rd0000644000176200001440000000346614616441764017703 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.Rd0000644000176200001440000000152414616441764016726 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.Rd0000644000176200001440000000141714616441763017351 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.Rd0000644000176200001440000000436714616441764015663 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.Rd0000644000176200001440000000147514616441764015631 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.Rd0000644000176200001440000000102114616441764015273 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.Rd0000644000176200001440000000252714616441764016174 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.Rd0000644000176200001440000000133414616441763015301 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.Rd0000644000176200001440000000064014616441764016446 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.Rd0000644000176200001440000000102014616441764015631 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.Rd0000644000176200001440000000264014616441764016526 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.Rd0000644000176200001440000000172514616441764016617 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.Rd0000644000176200001440000000140414616441764017245 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.Rd0000644000176200001440000000134214616441764015744 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.Rd0000644000176200001440000000157714616441764015776 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.Rd0000644000176200001440000000212114616441764015771 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.Rd0000644000176200001440000000364014616441764015150 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.Rd0000644000176200001440000000247114616441764015411 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.Rd0000644000176200001440000000140314616441764016212 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.Rd0000644000176200001440000000256614616441763015602 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.Rd0000644000176200001440000000072514616441764017342 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.Rd0000644000176200001440000000316614616441764020211 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.Rd0000644000176200001440000000206614616441764016766 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.Rd0000644000176200001440000000433414616441763016176 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.Rd0000644000176200001440000000144414616441764015511 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.Rd0000644000176200001440000000367514616441764015514 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.Rd0000644000176200001440000000132114616441764016213 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.Rd0000644000176200001440000000245714616441764016111 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.Rd0000644000176200001440000000226514616441764016330 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.Rd0000644000176200001440000000126714616441763016230 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.Rd0000644000176200001440000000146714616441764021461 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.Rd0000644000176200001440000000214114616441764016177 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.Rd0000644000176200001440000000160614616441764016726 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.Rd0000644000176200001440000000056314616441764016176 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.Rd0000644000176200001440000000075014616441764017241 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.Rd0000644000176200001440000000115414616441764016503 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)) } \seealso{ \code{\link{EmptyMatrix}()} } \concept{utils} SeuratObject/man/dot-FilePath.Rd0000644000176200001440000000115514616441764016205 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.Rd0000644000176200001440000000143414616441764017461 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.Rd0000644000176200001440000001537614616441764017740 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.Rd0000644000176200001440000000500314616441764016620 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}}, \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/Assay5T-class.Rd0000644000176200001440000000406414616441763016322 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.Rd0000644000176200001440000000165214616441764016302 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{nchar() == 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.Rd0000644000176200001440000000071314616441764015571 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.Rd0000644000176200001440000000102414616441764016552 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.Rd0000644000176200001440000000167514616441764017112 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}}, \code{\link{LogMap-validity}}, \code{\link{as.matrix.LogMap}()}, \code{\link{droplevels.LogMap}()}, \code{\link{labels.LogMap}()} } \concept{logmap} SeuratObject/DESCRIPTION0000644000176200001440000001160014616700266014360 0ustar liggesusersPackage: SeuratObject Type: Package Title: Data Structures for Single Cell Data Version: 5.0.2 Authors@R: c( person(given = 'Paul', family = 'Hoffman', email = 'hoff0792@alumni.umn.edu', role = 'aut', comment = c(ORCID = '0000-0002-7693-8957')), person(given = 'Rahul', family = 'Satija', email = 'seurat@nygenome.org', role = c('aut', 'cre'), comment = c(ORCID = '0000-0001-9448-8833')), person(given = 'David', family = 'Collins', email = 'dcollins@nygenome.org', role = 'aut', comment = c(ORCID = '0000-0001-9243-7821')), 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://satijalab.github.io/seurat-object/, https://github.com/satijalab/seurat-object BugReports: https://github.com/satijalab/seurat-object/issues License: MIT + file LICENSE Encoding: UTF-8 LazyData: true RoxygenNote: 7.3.1 Additional_repositories: https://bnprks.r-universe.dev Depends: R (>= 4.1.0), sp (>= 1.5.0) Imports: future, future.apply, grDevices, grid, Matrix (>= 1.6.4), 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: 2024-05-07 15:10:19 UTC; Paul Hoffman Author: Paul Hoffman [aut] (), Rahul Satija [aut, cre] (), David Collins [aut] (), 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: Rahul Satija Repository: CRAN Date/Publication: 2024-05-08 13:40:06 UTC SeuratObject/build/0000755000176200001440000000000014616442133013747 5ustar liggesusersSeuratObject/build/partial.rdb0000644000176200001440000016347414616442114016112 0ustar liggesuserss'9^tv]v??7BO5B-?s9#^o߽c**jD5[jӥ<-|֮S\X+9Ugu)޻具w{7; o7ś[ݽ?B<<}ļ&5W#l=hf[ qԘ'Pv׎G8&KB;-5f a,vbթKE/ "6F^נp@1VXݨY Q48Dc/FRRF^`?~"k^sٍp@69XIiSoD(F}p5_j!o(7q5pVDzb)/#@fم?#!!,EN J"b&$ܗEKb"w\X?՘^`#mSW QXAxmC՟E6M=SE:EJx+\i2wiNUz`@_XoW{uU'P [-PGw6 B^fu{~/}Fn.g׭:z&vJ{M+u{bON=@~cN__ky*ڼu+-R-[ޣu}/eU_^k_[No^/b:.y 0#!pF+v1[5m)RaHB & yCrTz椄(ţ^1H>%@paf"-b}dXMaKxoTi<\fUw7#'ŨTZLjA4:iBiQXRg2GXcoݪP 3yZjHK`YK/HgF"ә΢@LgсϱRgy.:6\E%tt!\>Z@`)2TU;9tsv$XHSWT{o_pE=6R8P_tN1*v;ƤsRy<]Vc- 0aG^qxV T]p򨵁֏n/J[\?7|qw}Kq'W)yI7ͷNvT@4Bi.?&UAT}v6ոlml?AOua3"l-8.uL/1 JTm QVZ@`›;y/څ&m&X;67w8䅼|+z^&fg'<*)}Drv,gG Lo~VZNZN.٣8xHsSqs;/CSW:C(q˝?lC5@P5ZZ2HzUNҡ(UEj7+U*>CiTmW^v>o m'_~r6矁~ʪ2 J yUmONn~|E!!h'8p~Ez?Zi쏳D H/Ss8&v8R]Tz&YklDgq8 t`u{}_29s8lG*%m*I9b5~b*?j8I |sx0_',' 46%Uͥ9B]lШr!f^B 5/~ xq{%#GXs,x@hkJF18 Ykk^K]KQ%1#i^- /@<3 ^s̠ǁ _>j =N !.*kN__u[J)0y,$nޒ̌Tp'u|$Lqn ;:g)έRέTy9B΃%},Q#<9ݥOyrHiD Fwϼ6lS(8FafmGGSN47dΦDpڍM86܂'[g{h]Kgp6DZ{E8-jL߈$C:63iv޻^^/5//w"\d{WiJ,35}oתG} ld]{6nM}Z-{K oVΗ-U0/wxe9"7ʾZv;e[G(ބp _#>h >Rݫ Ng6m}^7nV[(Fȿ@&=޿p$C=ڡ_}l4c&~ oLyxx_\B^57N>'ZSu;Toqpѱivi&nߧ#Ժ/T|}> j$k8LܜOk9v+kk=i$?/Z7$jnqL4i^Yxi*l;iW.cROѕ.`Yklv8mP# < Y"kO v 8"Φe(L3Ue9y-Z'.-DOH:T(9a~ Q [?F8Nr~z:Ekw5|Ş>'U7Q""yx B@dkn@ad,u䐹EO'_tԍE^//iFtfJ0U?-!/Xefڍ@?Hف3<2N^<ɃpJѓhh>/*8 C$=BQu'Ð|?թ*< ޑˡ3.{ݟ2Wd'9\ޘ|-dO7Lw{:Cw6OWX088܆S/׏Vk9w$:W z~ZGB^U}zIt,~p -ëK*=EZIX9_`=:"2j,9N'%D1l no)~i훵V&Z0"Cҡ_YeDcBNR6ͨj@Vm֧]Ԩ:?+&_B2h>,[G֚0H>K,K[ Osi /a!y76%b;iSl.ѽlYkITߖEv}%Ty(kIhk(* N.:Is\fu3h:-1`DKCq 8kə9XK/R`YK궤X*ĚʙK)4kəlkbKK>8JG:;g)NfG'V<|bnG #39)r>!ȜHELN@G,2grj|R}ȩ31ELN,2grz| V>f9bc01$L4˙ ZȜIQt\e9ӣ()p8Z^&EUВd 2E gwR9Ik$Ѳٔ(hSw(u~RF3O' 8|N>IO'pI4ə|"s&'EЧ S39=>12C'LOAʧ,2grZuYkwπ\,V5DS+g39a?kəlla9-OϙtHODL;с@Cz6)G_/?DKӎ4S=>k 4,Yc_ECȩX<]VFLW)f*K0b*N&G@K69%q ]ju\=ha6.M M0H @gs9u t8 Y tկp^g ;4ec #{_tjg#{Q+3+ȯzU; el_KbF;<ͪj5@)/%SE!-P Q4vXP.D/h3$ҏVn)RcHB &Z弩:+s gG 'ÐSZ"co4qν-V8mBB -CܬsJ]')6U-Mo1O~*ow"i;bAҮc) ^pp+ xh}dct[!RQ!(2LwaT;lM8Yky s$Y3KLZi)*FVb#-[} E`RcF+]4^4ɉȬqESI'v&eoCmF.m54NC{w 1_U[hU^2w ?3_|l)G>}'X M_o%]MiVg`V}[|>dSgSHM|tӴi"͠RKʐ|V0+(Z@`o-0LՉS@qa)BgfRjxC=7xU+sTtDv i M$pY Jro c>9jkкM/i \2FZ&1@CFjH[)L]W;0;GOp^`񞒚.`D'9xSc,(?лAMW&R,)}՜sKz,[qVy<aէg5}̍GӐ?=&h0Pf)uyX4cc+j 1as=hjTDCބ|ZHǐ'?QuWm'$A^KHShζ-UqXSFR9te"t~KlI׶߾)j]z ޥ?; RbHHYL Jj\A LvuNvө:m\g|Jz꺀#%Vۭ5Fz# dUT&pEqh\"ͳOȿ|C~&\a _}t 4Z~;s/:7'C,LgyD޳h׌֐'T/]cIx*&p ?6^rW(iOlݼS'}BLTH:YIWuMN N-y.Z$W[`,k6gudgծHk}~iL \$ "yoeEf\!oL 7>7uSK/%%d=όT?NB))U*A"pJf4ɩHI*5R@O.z@U.Kt \4A@ʥt R.uK R퓓2t\Uter5\N`23t V.3;L[ K]x@oF 0W5D=%WXmpEħ \!Vjy(T(z TtLo:]`& i"%i' 'kߖ| d-F v@5Lܢ3 ]NW.QIOw wH9"%E)rE^K@u/>5^Pױl Z1EY=qK4'nE ziruvТGY=٠GN7,2MR F^foce2x;/s VFܵN7W@+,2MRJ^aoң x=tHٯozN7Iq*d2;`QR`x,HWK V[pQz%4w\xs $LqUr $4ZMrj4EIT8Ш&fI3 L :RΤKP9iS' :R$JP7j/rJ1oź|I^B] WOr7i$=*UyTY !].JatB!96HXlظhNĔҚsXXsPPm:uf@r-:Ŝ賳00%U+ui?Kzvݪt( !( !a-1 n1L\6%?,÷*dJz.C^h6n KyVWI38?Eഇ3 [0[ w^4unNXƙpg7 /Ѯ!+O4өj{*&p ?6T_`,n˩S5y0yzʑ k4±pR^ɩB)=7څ:|Yj}KrHM?%m5f[G?Uut'wN ]LGg>>^k+ފQ~eN\!oL 7>a<,%R.#zR9PS@:z(Ym<`R<$`!LWTei3 22 UZBZ[k3[7' m\hbY$ig ($i`瀞*@kGt7v0UƶS(5%Tq!/f(,B8 y4}Pc( e-Ѷ  LrEM"r?QICf"d)ZEeZ+rm F}J/U?*!Jj &3c 2jwA5<47tZ=Wȃ0# <sBMAu 7&B LhVlaWY?HQOk׆R܋l٤bk ԅj* h{00يc&ClNĞJcV*', n.!MŠX\m^;@e]Ȼ:nT%mw;.%wh6UTL v-M.kӻ>8ON`bSp.N30t\!mQY QVC.v#QIʸqw6c6*E>+ɳx" jIb{1D-@AThnSu·ft>ҵh R ?ݧMF'}xŭU^*>ī?jeryiBW,.5e2K\2@ B5˴*&'ӱpִh=, =eZG,SHbСzT}FBIqT:D/!a\˹W'|P$qi U`9Bpo=2d{Ė{T{Cնɴp1qz$Oxû`k)A B~_ #lUJ~=|jM/WC깯g%K|rE8ZPmy^md{6A1 dÍߜQf!ۻ;rLcφ4 YkŢc/ 369^p|Ykf圂FxGa66 _#@{#YA8aa!K*g AI'kT w5UOPYS4׊=Alű'S *$1=Atű'TLOt2)XBg(9B'YT=Y5hC5o:Һ 8Rt[(T8<YE.4YkJ8@I64WmnKN _[n5"b5䯍u* v6wtkG+uHPT.@^HTp1WƖis\"MpU' WN7.4h+dR˴=Yy  kQ#.Uwx'msZt(zoo%ve~TqژgpHN:KY=qk]j؏.]DCtSE)vZD"[f:T,oإm6&*Tv\V=n#]o}om};4Q(;aSO_E+S Q4ԈJ_1|)n0Iil>f0x0Ĕƀ-aDE t2&DsPۓxtKxHiPYIKm ;:nC1nCoaܖV&W[D;>,;:̢rB$,l1W+r-0ve|ؔ҄wz.]fa#uY،;Ƅ& FdaK▢@ՐO'jdȂ=%[!igȢoeYdȜɲ̦/u+Z@`2dJ) F4Ŕ`?0"`RD^%&mQ%DI[hY7M&L{be+iOH!`DړX|"TiӇ&aSړԸ uck {YKbLuͬu#_r}nX7Ę龘ĘӚ lűaݒSFAb̤--cúY8ԉ1F$Tk^Ę˄wu~xR(!JVƗ,AWGTD}>ANReYeI~#ȏ L;S1Hh6)#Qy*5[%&Lqn^E 77'=|ZTN_T% G!4T.S<[ű1`DJ]O9O%? ZTE'O%ir xL$_#TjD+O%p*y*L0d{q< _#@{#FJR pBTFLjgYKJM$T|ZTjj#OSp)3Y~y*g <>#~;ضnJgfYKʴޓg%ԏh E`%T ^BBѴ<龘<Қ1V쁦d+=Д Z4L"8@N$K 'CWΪ5X 뛎YH8Rt|V SI*F"T^g-y*4(0"Oql$y*-nk^i$%OeR_:\`-y*b4U7\d-y*5b/O%ukSN7*1Ǭ O%)6Sq56 ;rNR1K_3S)VN5ѝㅼW nq-G!^1ytʐP] ?is Dy|8]P2swO߾oߨtq|NDՠNOK}r[} 8mTHN͜'ƉAU椄M75e|4|.Uxm+Ju@;M4}->b:qYçGIKmp]eߠ~s@HQyjͲOˍ̔MJ)nOͪ왂"_U.*d 3bjdնs ]5l( ԟQ"U ~֌5؁p@65q1\I^H[?皧~ zڷ~v[ws/7+874}olw+d?Z$k jDN9U*Lž!.w'b*N&“@K6o9tks xkƉ%e Qe;?g!k5Qd;?7ƴMC՟Œiiro @Q"fBBeHBKFxr0nb:X(j;]UW-*Ҝ| KZ m+~FBM[ߖŰUeq^Tq=NAj\W>SyiJ~_ +\i5 mB_Y{\߫ߦs n޿?r^兒Hven,nAJ>ś(;o@aw4W\w,vT}FB͎N+sr=#΍L! /#57O 1'%le( bq+Ao0|@m̂%C7=SO.pFvɧ#;wfmJLC~lbkV!5 QVC:fױ1fŤڳYEVtfa7$?ICߦ?PI\<؝.6%=BuOC>S8vxu'3ȃQ_UR. fTE}GCxR<`2 V ?`b|Q*AWt?i{RvNWYKcõĚϫ:MTg J3nC>;sYrgg'VOjclHLlv%啞fj`Y"=Fcnjܝ(37;2,m׀ ?hlT$p R:4\lܙϋS )_UN(NZ=X:mJ::!kmhsI3 8.'0 QVc- 0nS˂ Iӓ›aߣ+^!lrj&Ppni *O>$ §;𑌪&!JjL&۷~pmo $ߵН MQuDSC<^㥢;_p՝ֈCJB[3S 7&چKo}wK;Su+\I tTBE9|8lݚŰUV[Nk)+6?:f98/S>VwJ;fѐWM\yӊT]:hMYmkω2꺀&v&#ӐesDBj]=MQ/LBD,$R䐾6eIw(Sv1́ #V́ FM.R@:<<=`3I_^u-=OyprD%?Iq:E S\]-ӥ"hi.Rt\0EAD):mx6Go7X2c8z oryNuj^`6Wʛ7@M\RD"2MQ {V Q4h 8RQ+:97{b&߂)!o(z T:a$=񛎙rTOGMD&Kӎ!i C'N(M 5u:YA oN1G{|0bŸ1z R~´CՏJrXCt7.1Xku1 Q,YRtLq@bTqaaW!_MTT5 Q4MuT*J YNr~z:YDeM@h{T߀` i:N{\k Ǘ!62U7`V:DCVk߅bOC>q_A#Y%E`p T/U?-!/VXgڍH_3,VXNy=j}:PW:WhG_%m+a rqH.w{-ʻX '&G${^Edi85j[{6Ӈ0L(-ZC~lLl=eNUkc٭ZE^lFS)!_.:oǖH3:3ꯣF ov˹"?qj\kj\{w%\ᛵۯHqPFQ^%`+9#a>-KDXg>ܤu QҶ('[n߳ŭu ;Թjs~x!@&m6R%ZĂ w^DZx8W-(MEi~$Ww}eh({K:Վzc05$:jL%,p2O_+rw\̽j"lN"[}K/k]Ļ/sκmPuWN'nP,]34$I,e(ڒ B~TYu| e:ĸ|U)U(irTmhoDG#*& :Gʼn@6 {V Q4hsԍyۄC%RY#eޅ)!oM22ᵙ#t( yIe@`"$_ W Uh*jǼ&aS85:_,T/rJ1oW\T/t-dhVrAf״;u]بvmWCq _.5Uw8 yb1T:,Q /$DEFZqZ@EooGNJUթ"5[fDS/KWt}3u虓XOMRq\6|6@ѩ6hcZs^Tt g kM;m'ƞo1Zh_oAefm_7`j/u{tf`ړ{_J_&ph;#p-/N8=aK_5,;ٳVV,kfCR|> }%l㕖<}bW9+R]]$L!88<VcYz\nV3M4La;hb邉Z2 |hkGBS(Bs:N(uS>B^= P)Sڜ ;^@M~42DF#}vaD![XuVK{=T(i1u1Ϫ~t]CHkSu]@iwe4kRoR.= K'B~h̫1D7XrI.p&Ǥj#pM(iO\˽Wӄ71}Y"!j7LZZGͣa [о7&چNbԆGhItT!Kz PS@:z(YmOh{B{L300p8vàWU߆ ;^2oV Q:*ֻR)ɴNgX.z}#?xIfe3mșa;R騄(i{Sx'fޢ! +aS6K#I:~2x@z%DT]0"JR>LMHTMy, ߾5i6ܡSD"ȱ@n!?utQQd1azVrm_BPa*22Ffo]>l{tAo׋MӾYqK._ .F1`: yXc %l:RF$@8bj ,r\hoJ'}6 UVB`g kPd䫦RvҴ-CՏHb2/Mnoc^|Q/mq?u+tK?8 _BY+>| U"}{Qsh+sPubOz1lW =zFDj?~p2_ṙ5H;5ǧU7kD25;>W_YמWyV\iZƦE5lZ*ҫ :S6]Ug{ݜ%` ց[dZg8yh$lsm8jy?1{rTH: yb1{reȗrצVOqi[1mMFNk<%RVCl6N󣢆uJq4k) JB]^-mWפY=|> !]w*@ʥ-';'4sU#Kf]Ž#]k9T>bIE?S3E`=,䬵_{W!'e /Y16U\llnXICSO*caZD=L`Fkץz4PdؼhH\ں5ȥ3(Z''>#dpTa@Vҭ|w ֺ f!kJj.@^0lѹ+|n9îa1 hq<LjGlwhܡ3;q -79'6U!O׽5׷>! wxFjb$wTw BGhp1%;j[ZX(g+FT^p*ռ/ނWu}ϐfz-W{} 5z;ԅR0zK)TW:hd][JܝlwRS˪H6IzrEjT@~*xQh9vaT,'X@?%J!j8Qjۈ]%Hy9PJ/;Psr(ڀt[Nv1<=,p NZi[4c̗An a2G?ǧWu+@E\\>m:Pg&lL>uq ?k l ,c_]PP?3F"y`nzp-Pp:Z;ܓƜ1$z@d/N?S~(D54J[2Sm25-qu1jܒI"Eۛ2gX5OVBܚc2tZo bߋ2ϻ_Eӫ25uֺ*3'a9r5"div2ì$5YঌY4m:Q]2!k5Pd(㒖a=M߮,ap#& FL shfC1Q [?F8N~z:9 Mډ)S-@ԛpjcɲ+d5SǹQxsW%/)u y:QN3V6=F2O+m^Xt酣!MXmTdѹ/삓b/ijSMi Q,~Ǐ꣇՗Go`EBa'kΉN)HT29m{L)RQZF_}- ;.?ױsrsl\H9 W3a4|q{IVO?ti& ]c>ZB>UXsf VkEW ҕθY>E&\;[^9Z;6j=Uw8Yk-6OqV4k{q+ZWw!5ԩ" 3|e/ctq 'R+ QQgJeF{4b,mo3+DCFw|( zersΆ1fxy,F NHI2|FQ kiR>E՝JrSU&>_Hg 03:_p)e3eZ썬;kwyP|o*Z^fP`-V|6S/׏Vkx&V z~Zqi+ yUm qlQq͔1}DBk2 zt2E*e$m_>Sݦ꜇Zڐйp&BSȌL' zI}D̬ 75Ip a?s"pu~f˔ױڝIS9=z^@jg i>RH ,VًF}mFQiWk̐sIr*ƩX[cT}FB}/Gɭ.^/0"/Eo\.ȼiYŒEEՐ0f(J00B՟E/p6ccDj7s${m\k"@lIξ7M67A7zhGohl&2u Zne\7n @H&G@K69:=.g'~| $"_JZG$D9/DБ/612 UNBKvCQNzZ#QĬxCQ I(}Q/ኖg15g~J2mdTvG2Ж2R mFq--`خaӅ6 Sy]@sN1sڝbFx`Up@tN+V/,CY5+_ '!Oo%E zNǩ0:-r/ZZ$:EG-wbnV?pVg^b*Xsfs{yW"oC\C"t r"ֽ/uL :_:/CAă0`$m\2`yZ1V\PqwT\?gzfNtTaVb3R**jprDjk k=&ҒfIN6Q QVC>Ÿ\u )T~WHjXgrhH))+_W΂'QVC`Ťt5'M滽rzTmO;n)DݖK  C~< W'U&!Jj쓡zJ&}j- SSy`h4sGaˆiQ !owڝ\gL! tKh2v(NЕY⊦GX-7%Ӵ_82?y*NC6ثr>>I9PPun\>XOi0Rz6#Fp0N@ &Kx[.W4)s8Y3,0Z&iikI0ie`Aޚ1Rg yX[ݫOy K9ׯUB JzXBFVUFm5ppAxp(FtAW`jĐNV_Sި>`?NYdeM k-l=* FwZk"p򢽞n󢭕!/c?Q+XzI"oO11(˕\彪[eؕ%oskq>}ImJs4 C(+r+P[:~QvͺF:XxR`SpnͰ"Lql uvi@(_=?;:[4YM7',G!ڢԶh3[4|I!VȚĢj6-Z#}+f7.[\yg7]_"lq2S&T1b,UlߎdBIFmsj;>71$!J[W 1ƭQE`S*m(.h9tճb݋y!e䭆ePA[ ˆK?dQP Q Fq:3 #nl0+ #E~ Q,YD7#p76K|G00B՟EZjF1^11"jH #r鶁ǚh9D?@,w5s>I|^B8:o$qiYȳk.!Q@I㔋[I{t]@)r1{L0MC՟)legMCs7pVERqEK6Ty Q,f8 YMAG!`9x7-P$lZL<u tKw7, #2e *tm#OslCwplG&s+8|y@3lqghZqat9pCU'v+cGPԇȠy!XzxyHG8m:l&DtQ )0IC4T_'῏V2Th1pԮz rni%m)[T4[SݫCˆ xj @ vsP"6r̬vF=B*+#W1J=0*'@$7!G`)&b(N}CSJ- v0̵ al}'@1:dT'qڏSq*Gy4̅=שvk H1mȷ-.ڄjHuvZ3h(Z։"lkDxîF71~ՊS%/OG#-1M(#5zTT&N<>^\TY>֍=WQ)Pd4 Sː@ %DI{dq&;2dެ rt T]7paaiG.|kژf{qMQˠ֜0 Rc;p6 ٰ5rǀcj!ZrF8 Y'n? .8q>B2:R4? | 1R>UЍ0mSB~}leȖ* N[ζem^^,o/vBuk-?uS\YM՟uJZַ\zwRSN&TOWY/1*-wxO=̕0(֣܁g׵5u`Mu\.@^06p@YA^3 -6U" yG!ҥ893T,4ZR5Q%DI[ 9I}Xf1CD$WLյU_x9{W4t CL<>(>8DկJbOKSrˎNy`ק3h22c#t (2oaU=bSc>B*"Ќ;ͣn&zC%uFx|5pr\.JSS7=k3FMi'iz~$O;w?%jS6aQ;)[s~ωNx'L::}+!Zi|;Z1dtyPS)X dE2r~.)[IږG$D?[LƑMr L&2l!H3T'IDvɮKʍA^O&k 2a?dH=Exֈ*aBɹ7ˤ9 7:hl"vG? pֈj9-=`5)pxEcE Wh!m5ÞZ6Іޚo0=kTWKnl-p_ Ѹ;wr)EIL`Cho]i^ 5ùRt?th?itD'T# t@ZKU߀q*asDބ|xȆr=Kd(o(Ng`B{Cơ6dj1_<'E@Әf!bN!PXe\Hy3M.KaYׄ ,Z#Q[,>K+ӕEzB^P'i6mQs Z@`2T@%a-H l=)y 4)2?YDg%DI[h :HWAaBrHI~`DҤȽ JTڬZZ@`2D1DQ'6YZ"0*A[By+mvLa Iڤz%p3])Z@`2>F= {!hFA ģqTwUf} eڵNZ -79WpB~#[l/8jo:ۮǽX=t_|gZ~B)-qP]ӳ?_딢vo9DfMҩcZ);P߳ ^bT'Zޞz+G1%,BT9)~k_뼌wk QҞ&Y'h}ftNRjMJKlERvؖTۖB^nASSS^ QLx 4cS^/ߙ; ]6%I2o's)4<׌</ aDJ^.6%7U eAkRr;~)he ƀ-l$2Uȫ_ 0zXRi8 Yj=|ǵҨXxKK96-gP {{].@~>k 9VÔ.UG]f*:rZ+8JIZ:%. TU???p=nJ]Ti<\GuKgXe䷸W.*Uwso8ucU;P:d-L.C:l62P%DI{d /0ّAc?@H~X꺁 7Q䰰z\tξ!&/GkG!{W1xjC Lv 8<(@uA&Q0%#*-*H_(eSS v73j Tmr&Jء:h]@K'ڥ8E'Ւƻ|CE =It;(޾w."~ g#E'zhu¾O8'΍q S ˯f8h)Ri(B'^f7Ziy1+]ހ|J'±_,7 녱Up.O!?M. ?KK?̌`hͱKu}:rM2K\(Tp`+)sxVUu ![F?;:vS,3~Y.1/!IpU_xN+r/rEovzZ&eA~nC~~OW%D'֥)eGO̴>UESut (2o PU=7`1)SXs 1D5:˝"Ќ;ͣIAwr9SM{g fnD+r5#fԥG$Dk[-uxmCJzy3XG>뺦]H[tiQs eikk).˴=s n{ͭZ\cZ~ ^Z| 6Z:F3w ݰymxso_|~㏐1Lz7<E6is( /?<5î;y- M /Gx2ⅾݫ?Xgz+JȲ9ζt}dso~˭cc٪2 UVBKE ׼Wu}g18ˡ=^|͢j!;8Qn^n 6%l.l6;JDy@z.XCY[L,rmkC[װimȚMqIl+ht-vXۃ+PXnjv xyk =W BMT(iq- P;=CuIPR-^sD^)}Nr>_O^Z55ޠy-y @~>Xz''{bCT@YM:Ŀn 6_?F3n${|TEK|qS=eUBU9s>آAu vRSjnE}lXj`'f9CQUt: m:1DXE/9zfY 7Ԑ2u;#zT ў$[r7Sيl_k)ў)YkhV9:ZD{N"ў86ڳ hfS)XBg() D5&vgxdIGBabvq{NB^5ZDsRpKK92/cwVm5l'!kZrpղF/33HeCxcl+W߿'3qRp^8Ĭ/0:NiTHH6R"Ilv$:wR¦H|2UtJ>4U@SBz FqnͶ%c@MYmϺϸQ㨎ȈH~RT&^`?d}˘/(emI<'EOᵙ}T=H<<+>H\yD> I6';1tvߓ^(Gg!ku(jDjhj8K|ibj8Kqd5-Pg%lIȇ@jZv8UZG$De%gS24-#e,ӼF>)%qEN)Ⳑ!cTWbcAYÎ&NA29:'^=Յ i,!ߞV,!&OOotl:, ߌV;kYkjy!6,yB=P"3{͛]pJ|^3Z>)|ٞVco^u3O;a3 uO KtjbОw|l6L?g ç2eEQamݱz nMۻz634"̑I{$lo/%֞)ZQyDv։S%lʄ5*Nf~|T4Rq~3}DEPr010;fB_r&!OcSuW Ob:T,U,֬a:v6S]>֒@Xv~>͘t_4ZOYfMZ\OKiЩ@&ӒH+fbzzbguq׀ 7:/̝o%DI{΁[|RԎ9si3Z'{Myb++1 !k?@^IUT# QVZ@`2ֈ6.m6m'R㔄_䟎r&5ѶW#iKK; oW!Zm cW7XK6B5[(kuLz>Ęə9>>,)~ye ҡs.J(!i\Qɐf g{Ni}61Εf A(D^t\>=cmx h.D՝d'Izbv>ұ(kvkٞ:fo@֞4 4 5dެXdւI"!?69W-) W }EmE?JZu˼Tq+g-/:ϴKոW ; eJ+_ {-u_zW }h}}2db1T5Խ !dJ1Uw¦ UHBMR8} |TvDU Q:JC h〈Ψs$<:FWiT|NΥQ~ש"UK4Ie z YZ#>+ұޗ k͛[~ :UZBC5^R_n.wwثT(1fnfQG+Kz!)| Lq99xvנ XL1u4dsMw odog5vIy)Ey-,EhE]Z E5:H vޱ`U_BR|nMEŸ7<YkWQȣNGfϔӎN GOqPurmR"-d;Id #U͂g>%)U2sSpkS]9EG9ǣ,xOy0X!T dz&y;<>#sЦ-ө 7AڜAJTq0a fQo$ NG k}^uN7-9dM'!<д/nk:~.4j\Y#- 2v:sjXPy Bih,!p^fGyUT`{ 3?.dO~OTT= Q:0-JeTRNA SƥNͷqc|kts-R}f 0RdZ͡W~[r꿖V_S"kA(qU 0!وbDypO o=ش>qNOؿpft T C o5/^hsaz $k#-`Wl4ĤEpݝKXzܿ 0 fЕ_Hn{7Y[-/RՌKʜA is>&*{H@I(d nfT}FB}TZwIb*u/_ O*x.ZXO_Qr̗IA$ _R ~)V]L3v\۵u&^&w4~xl!N;Ֆށls'&=p^# ޣ^xzZZ^HUaמКmjtuU=`fCb2Mj|W)m;TSuD ּ2thu8YȐҐBq`rV{4qCB,EثN7N{k 'B)O+`3z^R(iׯ*nqXU0i2Yo8/ߗ[t6 nxz8ey$wm,}9O;K=:RT`/f=̿Pqݡ}%큃tJ_tnKmFjFː#)vA^QCO!kmY{.VBi) }ʬ,Dx7ju$EC>%- xr QWCC(IZIz_-n*./nYXU~o%-7ݪ/sFiu]C^|+&Rgxr0T5Z0sQ.d"]BŲf^uҭ'1Zj|Z)eY)|…[3SM:O ,H7;pTK`r>Ó5glT Q,}ҋY~ StY(i!- [탪i8)!ad[|c8npxfj˛?g4++ Gנ4|Hl>s)Z|VVKF!sc5qݺ/(j; Cn?o_+k JI:αzHGJ?4E~T5s> ^U=Дpx]wkJW̩:3s|*W+V)$!t}PAnx3so**J߿ "gյy E2C[-N O?)2Z%Q;F8 y|Jz,ꪻ[&Ղ)UȒPl *r!qCuUB=B)&T<|Z0yşG=!4%|&!4ꌖJR&C&HRRo4zďЌpDh-BE=}Ёm>)YTQi /s;wn-kOP3[woMMe %{!ke kPLMOP 3ƪ_UYG)\g-No|SP=_iEw֖PK(Nf ZY4"ApmpK.-QR]Zfn)ط}gXle%/sb;[wԗ9hHho9.>-.7uL'嬑.TvBEB)꒍1JiLʡ9ۂF[Vǀ]Ym(>2Զns|N htOh(ؚGo>||;͇"!<%Dxx7ЌpDhW-Pxj2CJ͇=C͇CF]O09ӁaW-P{؈g-D˖c TgӪNk|f-aXha11r` OCI*m xU-YsKbzH+@).\ԜA5Yt9 \ N/JbRxM߰b&Q54Śjz}_X8{Ch\s՘ osQ }KtHO4G ;с@?r]Hbl?]Zף 9{eڈ_x]9nymu|^ۍ|a~n{wl-.kpe@fAV0T3Qj&]_EBz3~o./Wti)p]Oo8' ArXNaa=;2/sD]K7i4ﻛؗ/ݷ^1Wd ZC͕2 O'xk_Fbt.qb<%DҫWw%\[uKk jMu[&!Q(isyv h/Rj#4e(>4Pw/@jZO;+#rDe DՏKif|qQ>VKxLw8H@xictoӳM^l|5~%wAIf4I_BV9Sɗ<,ȨgC!pä%4ikT(2鳗"!/v*Yr%F307 Di^y]gдg$DItMC3h8dsR_{;JS܎.ݷcd}-y߬Dz?(F<,Liļ:j-MGw_+;uo~nRlJdt'"{*1 #?7 $!CO…sihC(En5gbGh\kls-RGs09szo7ܦ ~(cI?HgFڴuoo#>ZȀ: 8ڋTHS(<|Wze7xCY33v޳$5zN!9ƴ(t*F$^w*X{}B:8*[A||]nU^BN҇݊B:= w deu }'v= +-bˣ8_=7a(Ht֣8?1GA*e$Lƣ{᝿CƳ9+*;'4߫0m=RcFB;{)A;iSVoTGq$}<NPⱷ :qdQȝM:M7u5wR0C[s> seKՅYA^6 Se'gF?k%Vk8+,ơ$}%E~vpd0VH}DJK$ZJZ+]¯^bnTbu b0҅R sVx .1 $ƛu Q:XL;])I( kAgNߵӮ409bfÇsAjY{Hѹ }'v +-b˹ƯN 3 >TڮMOP~ȹ 2&\\new/n`S\ڇ Bfi{- Q:e\O{'¨= )s)ss{T(4 z74uCOiu9-c:8ap9H Q:r\e 2&rm&ʕwxX}!}-Gj\p 8V‹' LKQֻ4'{TPUmA֚-}I0i1 6/Fރ|ϸ){.U_B[ ^AF]w`~("y |$2Ϩ$D"!&Ln0H̦* ǀCVYV$JZdYaq2UNBή O,C* 2j ڋ5V~5"HHx'Z-CtURt Zdat!ZM c>?*15`Y5@Sck3*DuLގvml5?H·N5^|xm7^74p Q4ԈpSQ%W g-1R̼~{ oxN % q у/A Q4Md|TZ_BV9FLQDlϰ4G Xc>?|6 ay;cRs [~V:}_@~a7V. 8)BAh$?Uq+bR՝g&eOWQ1P fh!&eƀ8B՝rH=;NpI,Yk_ht]|Ln Nk3h3âOW() -Վᐄ(i\ϛ_4zRB Qp|UudЩ.0aj&i6uyi A.(ryb ^М?o?\'Y07JOYc]B AW[&5c aְY?9BP ͢kdcsBt|=_uwczC o#!y&f\9|> U|cxKEwOnǩ~7G`=Dcqرyoe?/XM= d[p-nOS;*P(} ?:EGȼ:QL  Q$=*EG@MP2(Ymn#h{ˆSt3w*щ(; Xár1z4rb>)xD3Ӟ-T+@bFBP<1,3W~3';py&*~^yᝤ\\} isV7{V8بczTxZGKQA \ YpZ6稰MǍ8pLXڮdv$Ӷ U?"!ʡ|D,d&`GMʴMj5DdnaE`FE9Q6QgiML 2fᯊ[ǫVrսJ!搹E+$DOIiSsBXU8!rÐ-83ʓ&"'+'Rf.׀s笑zvLSy븋p 7@y(>,W3fiw~nom~t Lgn% /֙#_w;(TQ' ):oµ,ZvYkm3BK@}"Gj,p4n'!;,C|<N|ԙބ|X-nn~-Ԍos*k)v*'M5(~ }Z'5$_;1jGCP7UZᤄM' :NnNUX~V]LAgQkW8mm߂Hѽ/Ń9[殓 W ʟ-F?@6W?7n ȧR^iA8w--/kɇ~_A69jUtsp;zZM󜁭 %yęcB}ѰEVQܚUu s M0 ƆYܱuy/_B~iޥ]wwßyveReSg/AnN\BMMT:d tsR d=b[] t |an>s1dS9npկ !}Z mlR6UU/oZǹHho7X3,~DSSdָH#FׁBi;WN#SV*6mvOui8p-; #j ʫ5R.gJ"/!Run9I?7y咿(Xtʌy+Yaxi84"?8|  *IOjQdW/i!O~bBfND; YhYL$GLJAgFfҔBjen8䟞I@s4y||b&p,ƃ`V}%iG&*n9CnrO@}B{i \P0"p]RTמH՟)JkZjHGRLIubи e w>T;=iw^t2tG={GfA'T/LK޶'uW!&?6QukYsV2_hΟv^Nt=8jᓦ'Uu$ BqsH+n\nrj&Ppnim8gO k\oIaBUEj(i1l Ew"`-ZYt,~)b4M9vv!$[ꁰ@PBݥv$Uj HT]pE#mymO8YkڱN@ؖؑV 0(*OP{zF uBY lR鉄(z<vVj)m`-?Hgj{ - 2J I tTB[x'fSuvM-#hxD nX b`Su]Qȣ;$w@ ˆC,~A¦Ch6/f!'s)$?zQ$DI[Q?Nqөl" _xB~3_<#s\zAk‡vw/%|яG1}n5ǮGIQfp[1e;F(xE<}V* t$fUcpN=TR`OHYL}vJtRg*x 5P- \3 YL,]3 /A<9@  ρbgٟtǮe00YvL ,K 8.e fٓ?i!8D%?YÍ| 1SZsSCp֤Ֆ6])WXC+ 32% 2E+ k:AW@LKܛ Z4Y<3TG`#fr3 '!yf,X=]ӽnr)}S})EMYdɤ|"M&ŏcl25~</VmG~\WuUp MO(`4!4r( Z^laW(?`oKс.G5%ikE st \cސG,j ]x'@;_Iسjbf44Wt4:%A:c\s՘qvr8}P%De[d)(j xY>?*15v,` f|}hT1MN9p\͙5ovI[X|=](M55.ZA o1Vdj0ՋcAE\nyZYk|.c17mPcزΏn;fqG'aRNZ8,":'Lա/!aWIVYOn6\G|qcnV;55-tf|)oZ>^mȷLy<" .#i;E s#BiEo8IX$$@qz1 Pl0nVn{ E[q:MQG,h2׮.?I/X=DR;Uw8Yk;68qV;j{q+Z w!5ԩ" 3|e/cîİIWOTW= ZÔGT67ޣciSSO"e*g6JCA*rsΆq!35J _ gf .aϐ(IPTI0d-Ou ŗA@m5lb+_]?_w .Se/iy Y1yj')C.3FJ ')s1\Uj-bNFz+=UȫoCO؈ '> gqI'\ĕHLcJ r D{ꨩ:PC"xEqo%0<0x@S)S~ZBxfjLqZ lš5aD`+[MZ|KQfgL/ 灣%FR|T ٨ i%X4SX=$T\\SI(*UjL#[YroM(8 ZF NӬU4VpR̘#^ qp52@{L K 8^%/NT`rSAT+*)~^'ȨV xyEFJr*׈V xI8ZB9XITK6"URdGYKTzFDJWAʫU0850jK"oSTX*2Ըa K|Ҫ:uRbmFTsEFJ3 KuCUN,eS xAh|O0,kNq:隍֯C)ph Qt$S(?`O2u:jGיQUC^73CoH,2UZ.E#kmj/28"Y5D1p3@3eMᓌJν; y8}P%l djͨV0|Bfj5Sw,0@mD>>U͘@AOZm`&&kl61P;t*ygp JXQzj\ijl;Qh,]<@ :jƸt!DOJr،DCxY-؉%#,U>gZV$Dd?xU*9c99R0*"V\Z$Յtt9rsv6v Vz8k'HUTNrL2QvgXŅD).ğiy "@3an@(E.̓ DՕTj`fTLs֊^I#FӤq 7?~==Mbs/ϲ2=.ssuX= e 6Ot;@xf3 ۛst9̘I73R2 +ƊrqGY! CxW?t!23wsHεg%m.SwG`]~:ݩfǓ\Mp>'9R[\l O{AS0<\?Pk%#!fdSXNt GtuԩgȵcЩDle1.i!}In:u\Z:jM:a't{B(U3m;?6 ;X^1Y]wy}B¹\l.b $f &.p;5)ɡyPz㹝Rs[n?1l=<6*ԏ,J{lL5}o%HwjL%Lu"j3WZ%!QGOկsÐ-.bcQciV풶KC՟%m^p);;8z@㤗VUj(6 JP sEVqti~<!)"F^uZP&|QǴG.vNBtB#Uvp$;rN1ѩd˅j?s!_L=!&3cK FͼWv+z GܲFZov0!"ݏe V!?N"wW-r|ΟuB C~nNJФf gZ N!k}3WeUx8y }c D_Ň}Ef)P&4Mq`stDNA8YK &q0a3-aӬ4.UTm&< YGJӯc8VyvVIG~" -Yk<&M QVc- 0!BU˂D[lBx=[a;5ݵG,NɞI M,H hɐh6UTl&ck jˎGa%W<u@̋04n͢EY JjHsWd7+ CftIq'B.e@'@Q|ѥ,}%p|ȗO>30}}}wKEt 9ҿy'$aoJ>4B?%m5n&a{jջ^J8yt./nnq0ʯ0 |Y뛊_B2}~Q/%DI[h|pfpEldh{l4Gخ=wղ<79WpB~#[l/8jo:ۮ {a 5zcǖԴP*%\YM՟uJZַzwRSN&TOW\j~*xQh~aT,#D^9N~Ly(UZR=; Lh1A7܎CI}՛ېN(LG(i+!]wnXD"’ KQ4;Y:tY[BP-g/4 =җ˽0)ΓTZAzcF,T=ZڀH>lc#kgאNBY]8Dz.`Kt B{ΐ%BRax^dD:pl::Y/9Ӌ|/ Ϥ잪' >Ġp?1(j d~U{>/yHsqɓ^|3TNC ()̕TeSsor&_B6?qݷEUSW_|P4bb7]/Wc|dkѕUlrS37Y!֒J^|0B,Ti Q {sK=a$=ݹ$m3~obԿML)D-AޘfDR%[//hPvŽ7g-o_K+h=qW*>@݉Lc5DIh!kMd=Y1lr DdgqqmhҊ9)G!kh1{FtMo^ĭ$-CՏHb2HVUV BŐ5m[QRPQlwhL E!^4b ,%jsb&Yp&}3QX2[H00kȏaBo$~RBۛ e(4LƛAZ$e#iIuS B8Yop1U%DIpSAJRIuSAr:@OIbk&zImoh9ÌdfjZ- qFf3Q•>Flÿ39!!Wl6;5*HmS16Hmᰩ{ךm'}hۉ ݵضyp-QYۋА0z[Vmod&ҁ6&mҊZYmcZz?cz>w@MVO_4D' i#Fa9%uˡ0[*>w0)3LR`8N/m9egZCxӄeB(f5̛,eŤ:JbG*TZ ՚9Ьa=̬r6}4(+#}Ǚ s,*'@t`N%7kS31N0s;<" 2;T;cTNInu LfS&pp?cq#].g!Ϧ1^L8yX Z7"MN]99&(rAfkF9C9Gw0DdB{̓^@;ŽvrvrdNvPCb/bC*ZC&OȪI/=exwDGG:v^Y!g!U'.JUߥ& '"#G;EE[VEA ۀ}p9HkAkjC@E iJ&1|@=MstC(I]09^y$_˱"Q =dywqO> Y}o_u6fkɘYȳ>ۢZɼS [4] UyXGjH}èu< Ӷc֑N`t:8!{8D!w c;;; IGS%<GATri;BHb诿@jP9jCFr'm"mƷP Y?*#h˚_GF,3+}8hsv]T31S>e)OO+RC6Jas6>>.h]Й rWd~d\0 6h%MĻ@1RHbd !g)n3`2wx[M{&Yj3SI{ݡQ1K3* Zw/ȝ\ c{G!K-,{;El"OpE 0l cȯ6S>ؿ%=֭"mH1JY> SU81n"mP tCb6Ho#l })%, R\nT'lOf2yk̮ex%n*X'v>,8fv&3,cWʹ3"mƛ(  0>FGL"R%6R %m9PC7,d٪Z0Z/|Vyr ~R{XXOS"mƏQ .4maݿSsfbbQ5_d̢c-XnK_ZP?/2 <Yj[oå _e"H{`k;* oL;H׫jO4'C$IsI^\@CJ?cd@#4W,gNHg@z57dpp);kg]?E! {5x +x6 J0[tpM;a'?pd[h3hi${>}00ƺ}atuQbO}]IDg ϦF˦N}N@i>>@ue/}9mD]I6>>N)3CRu Z+pR58Y 2i 8 YR3Og Kb";< Y} Q,I/ʁG@A]gH:,w_S:d.~q dwYˎnY4+뺧DB`u[K0Z1qyH`[ ۪vykZ7yŶZ;~ )" ͙x}D;p n&He9 p=ԏp$预o3\ndr!OI'.ex֝Z`4.tb`T#tPd?b=Y\v^疻2Qȣ'h>EۿzHߞN:p"^|lc#CaIz' G(ʾQNAzԅ\3pE jܲC!b0n5*A{iP}*$R'LHP03aW! jDH-=>gsK^AR Ȩ+%!KE~Ѿ!wAޥ1QzÐ_emtsjnoAN1@Sy)yCx-klDYm-+1f (ub 0lp{FwsQ;m4v)AǢa+9>Z7>"n jw{ D%!x6i/Rˡ HcCpa?;]*UH+gw>Jd[$ꈠ4}*l:;}W]ɚ|os/.b>cϧqly/>89?/{_>:8FvY> 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 878 /Length 1476 /Filter /FlateDecode >> stream xڭXn:+lוH II`]uCKlFC傾2H6sEc xD̗{̏"<}E'π 񌙈}¤LFr¹`A?cGތ%18 c#zuLO Y|1A;։ @& DGpEĀ4@Y`СA'#r>>>;A>G􄀏!( vJO "q%"@EĘga: 4 1I<Lz1Qj> B dDPRDP4JI#R;"(eB@—!Ms~DMbK Iz_*> stream xڭWmo6_o&b+4/Kta%f"I~N"%[Hsx ><_Lg`?ZÒ  QV:ӘS<O=gK?@;"žTzBE8myQsGxxfvJTQP2!!GQ@qH8N /Hu7Y &QcD\g<:acjjkY&L{!W%=2;`h2ȇ0!"1i0#gЖ߱uT"y_1{qc'o8{dTĨIrbļ-4OB)pYZ!b:1c 9 v@]m\^ h崰 Y:͚7߱q*[3(-j>::^,e!5s&- ;`CIO&Qx$!rv}Rvi%q7o۳>w4"Rpi1SU;Te>҇6`纤 ƏʢzruKC nQA>N~ )yt7xSt#^D;~~zMH<}C:8ϳێL? ;-j;m_k]7ө%Kz].SUפx֤`1 ܃4qӈݞ@٢er^fRoQp\Pf:{e,Q;,LD>v9kCK2ODյPx0g6>/&ѠvQsֱ@SLè13_a ( o5B"2h w0zKV0ZHCq2/B['JQhݛP j;k϶%f!U5ͥTٸ[UR*.ϓ9q[_ECn);e\@(S :p->!dIbg#kRК(d !A!OJɶ0B^(ax1Qq8ͣ endstream endobj 600 0 obj << /Length 857 /Filter /FlateDecode >> stream xWn0Sp8^0 ZVUMZskzpCa4׆!eSCt2:YH!ANB@ vǣ@մ d+U")t*YT<}mfpΎ/>1qd^vd͊WFLn#KxIηaxŎa\+ _Yƥ6o( pOxxiCQ>/7\C ߾ 7,J{NnSfV]tꖩr\}a@MqLqلE=אDWI]U$2/62FΚ KŎZyB܋rDg=7$KseŤd^H];,#]`1TEtDWUԹ`e)fG`J$ݍ: ۜgf1%UΓuG8փM AX9HEv{S5CJn fZ|?'QD-u iWݸi_趵ވo>-oMه;q0~mvZy !Ύ.9O>b "[WY?c&;O0֩nѮ 3X!ADА7?xZ˸)|IKz&+s1#BKw6o'0l.YGq7@5q9 'q.M/b'Ж}yi!{4hL{@ҟ'͗Q;  R0‡3S-j=Teօ'W\3T/ Ƈԣo3^ty4쮧/H( endstream endobj 404 0 obj << /Type /ObjStm /N 100 /First 882 /Length 1947 /Filter /FlateDecode >> stream xڵYkS_1*2U,Knٽ:|eMy}OOxdfᙉ])T+CmhQ2sBY500/\yFXHbṶL lcR*0aCh&c ZgXt -4,4,44Cɨ@gJL$a)CáaG4Vf4aXYhfG>ߔ3ّ^|XF-hRѺi!hģY%-a FPrP4^cU ` 4`OSaA‚?$Av G0A @R ,&) "`bRar5PF#쬣![h ,`˶2xˑ- XON'pb)3Xف%"(h_ Ӗ D G[0謃2-es46M>V+w ausƻ90{^@c0f{nxCuZZ~VoH/4U.(g⎋:+֟t1%)>)de' ;fM1kjf AvZr1*:)esudž$c;!^ if3lކu {UW6]muAseH&/h U]g@Et𜮝Mt\eq93;o-d#eβϧGݤil\Z\gRp)tf 2D+6+M Kw(]p`JH.`"8U{V]toeo 6`\:\ȴ[OW[zVI. `E4֚ ,f@PetlU*5}CfA!+v yS~ͧ%.UVYC^vup,}Y<ҍ>P`;*ZdV`tX  kYYˢ%p O WCjPH Rl.gş5_|X[~*}!jG_t|'+Az+lK ¶h`6Y gE5:+2l?켸kld'ߓcqO{*}"jѱۣcGn=: {rG6k^??V N 0QY Ds?hN=)=W0*GF7u endstream endobj 667 0 obj << /Length 1019 /Filter /FlateDecode >> stream xM6+tR)R޺hmK#1Z}:Yt{عX6LY×/!WW? H4V_%'RqFU}OlCvPFi940 Ej]<ޖƤȦ</diIx!-c#GVu(9!xK"˧Sľ(f1}74y2v/}a^g*P/A${)P'p&(soQ8@Η uQVo1q62 nwMR[ځaoTod#0 ҾlPrЍ)|.~˺Vk:BoLזELd=^ki!a!!67p3ujv7ir8wjwUSRēu>1;0wZ=&(S&efaRyމ`o]pȰc,;۲~.͒])d )CȚ>V:UC~DI#ϐ_5ʔmc- '撦H:e&Nc̶:G jl~1ծB/к:siCFDž'=pڐKI-:qu)|9?s+/'/_ n!除%8V 8ğſ ˾零lد>nε? K> stream xMs6<3%$H:J3Lǿ/@Q8JEi]}4qq.&/&/9sD 8 Xĝ fY;7Y\8OF9Ml8DS=W:k=l]Sc2Gŧ!M̋qs?>]LiOO$TBQʥ2`!E' ar共KAaU:+b2YVe]pU/r)AI,U~ 2wχ~V,"zap9?q:E\:e+ɔ&X%L&Ğ[!F?&()((z4vFV.ӟA yv@ ʐ!uMB@WA.ص|A >"vU\WK[$襍6 VfD8E "%`c࿷,t{+APPsndwVr'{paV/Lݥ ~k[iҘ&X$>|EG}'|y>ga )C^Au#} ]uuڭrY{;c>!yJI{6NFux=ØG3KB<Azo79TS؆4T^Y/omdv'Vew(zG]uۖbSE> |+*ݱ0lZ7 MV 5شl db'!~eښ`> stream xZ7W{H#@û d#!33x d>ݜ56|Y|R=j/pH1r^1Jdk1j2j.c T5X*ʚp* J5QF4-FD1JK$'RI<&c0 cTܸ& Ϥ.,GVjMzf9I.y"E`̔IP$ݸ&Qɧ$-%-լn*X (3< T^}1Ut*XVؗYPWȍ}JՍ=psc̭bm'i>'X9YvxҊOkd\DE'X-Y "OKl'5x֒Z 7Pc '5 ƞUB9@hȹ.HAwVP4 >w,ymln]qExP%=j)^g+C RrS@Pe, pu1JE!x&J) bNbPECBB3 9#Nrr)bPy-28V0Q43G^~~m+q{U7qɄ|Sy`uz"ߤnަ?r=?W_gEFyxʤY?mAo#z^ ҦE|C_C N:?1OꌁQD e} $e@(^h,B}׌'|wEw:S'Ưno^9W^~7N7е.n?s`9/y1xd#&]C!9c@˪#&uA-K(S11Z֧ 1y> ZVQ7O1g FA.x}QsƠVק 1g &Q7߫lu c[FXWKsƀ#8 2 0p?~o=+((q"/U#ǜ1U#$WG mՈy>B,zg]9/'sƀE#{58 ~1ȅ߫ Z ~sƐij#{511Pv^ \dWQ.*yz[ y܍$cՄDYp7geŀD^iF-s1g Y\Y+8k\j\l 5OTYqw@yBnWei[`y*[F]7]]pw:uH7e|"˶wWDmeYqwȲge٧^+ɲ:Wg ovޖ/m8E?q,1Rc<"k!Z"k!Z"k!Z"k!Z"k!Z"k!Z"k!Z"k!Z"k!Z"k!Z"k!Z닫8=+VD\vYu˫Z6QW+gU˫[`8U]Uryuu M1\]UWWuUmuUOQWmSU˗W\^^5jryyU3ȫ8~mJ ~V^vyyu g=:A^~yy˫./nTy&Wp&-Yy&j-0*G t endstream endobj 843 0 obj << /Length 1627 /Filter /FlateDecode >> stream x[mo6_ wE14mEvNHX,e5~G[FmEݑ=Gk{/FSHI*+`^$1zw៙iM҄7:Mѩ\XHRhV)̽FVoAuoE |K{JثmW!c';`/$aƜ_T_Ph|o#kTٷ d郝_O/k"QR!w1ɷ1mh?&#N $W{ˤ0Vb?Dڈi4d7t+lA!p20pT7fq=ۆ!B9/= =E+gsw1 6^& qhW5N΀.|VN&HkN10e, 5 =x+7@Џ@.6u<+1l~(P)N~J6ct }.ۺ_CDov6ԧ<w#o1|GߓĆn[ -!oѩ 'CX^Hwu,Ri)".o螟y@Z 2;"$^29Zщ AgPν߾Î_rx`$9PH v.hTLzz@7@mS& 7uWwUVaV\+]US#VT,ytI4Kb,+ ^#ƴW'Y> stream xڽXr6}WpT $2v8K&Mk+}Z(\T~}/.DKx@.=w76|;f.rɌ #fgQ4srF_gw|}0 [Л$ 7/]<$xpyaܸulRLӂW/I[1xx,Gp nm{M&Ý Kow|'@Iϵ aF_0 )`) /o6pcmL\\˅\Nv^(H=Gma\}Ġ|&{lS12V:BvqYcƫbc+q:0Yء n`&i"l9JCR~ʖ`,4xgI*_E ٴ}>Z>zsrU$%z :XrDYnb~L6_7$13/ȴe!OuŁxrVmAi?!ؽ"ԧ;(Z.ېUX 2otD*CLly@!y/;3C[j_ϴ> gb"t%SFTaW>TPi;_/#1{D~ Qep+趚xٿjcҞFree,Y-Vi!"_:,nd[ e}? C/X~{ mv']Q8\[NplE61aਫO^$25]bZכcJt6k1Y2Vd",B A̯PLd1G`aru-f٤4/iざfI`@P@K/<$-˼ _7/*LChH Bv:{@H=1pjhps @YnaFиE^0yFG6)$`4=7uԼOZZbx,OhVȂ!1- I}#, VI"JA+𳎔őDfBX J'OYx-#Ӯ+Fs[m*?Kns6Ot`g$e2km@AD]kQ!FN.qpA$<~{q jw_~ԏ'Oog:'L<q&wRoN|8s}>Us'*B*z)޿R>h4[@8?G^6[Ъon$fy9겧kZ6s0a3]d5D,h_Im5*ܑbvH -REź57өV}ЩAwQ@'u?Qʖy-4וg7=? 3#!C YGqT3/k.Ps9vIkߓ(Y?-׆f?Q endstream endobj 907 0 obj << /Length 1130 /Filter /FlateDecode >> stream xWK6Wɡ2fHIhn 6 4vzq@h Yr%99ԃ=Ţy}pFcj-jzVD"bJ=O_M<ݬ޿zU$r"ZI, :zZ К90tHD̷4ͤ8IS4^#.pw+P 7H~íؕ!V|ܐߔS!\2w)+*]4@×TX;<Q4ȱ+pOQTP\߱L ""P΃^MCDH HQ;R틄!r<pL3ҍ6+Kq6˴tn׹̊=5sGTmkQ].T t)V'{]l< ,RGǻf &22b9(b. &&a@ tȔ|Mʜ+omdq!V_Dٻ/S\mTVs:FݞWU.8 Ekff#b~/|ab";?A.Kb[ZUy5eޟwS٢| QhɑV p' \֝guscNA8U[s|2Ǭde .]\;-^/Nܫ=GܟC;4r`8G'ޛ3. A|~]c@)Ս@i ^7LOcu#ϹhQc:bZ|\ɩkب|qZt <&~ 'GI+nƼͳ6T%~͘>3ݮ}_v܁B@gDM9'd\f `@^כM{q!_.ͫ endstream endobj 790 0 obj << /Type /ObjStm /N 100 /First 912 /Length 2653 /Filter /FlateDecode >> stream x[[o\~_ay83rXna@[:Jm]7g)ʭN9B K6~Ff )́q%㚃eõRڜBckPS 2[U%Rˌ_U%5%5sO on9 񥁦n\% p)n4pM R ͉-H'nA(dO!IB7U4R(%'!7qb AZahTV4ׄ7bO:B5/#0 ($a"j^|iKe%R{/bp5Ņ 8v%k-! 1/7QaMfݴ *ƕƤ X8U|dYXϟadTT@)aB#Uﮚ+yWblзd>0v~Z \}Pao>ߡj;Nj #ĝ=teMi-\֜uCi1 |cv%vm׎ߘ=[ ?0\ܼMX۷4>VEE|$&]FH dógax?m~؄E/g/WW?Aw(Ǧ:͎D; #b0y[%OEKc(-)P-OAkz .%JcBszZ \dI"ϏSlt4`Bǐ,r4Tc婹cV[; YZb~;`(f=feP960fq$|m$w`C"x;=[A rYz@3ܖ=5 B8)mDL)g: ?Bk:+V"OWWni_nw#ӗH^"v-XA Z n6o.7 ^ »"xX[0mhn>ݜ_lXz|gl~ h]y ,) wY`Z'Fcͣu tr,jLN7֧FQ׃T0kSeZ;֩†N.T]"O>2 C2bWbBU&L†!BQdрh'^FGz9T9 I(r_0be2W\-QyIU,l9W)P^{ g=$k< ١w2cx|w }2nn>! wQW_ *WkRg ^ߕR~WW) XŐ $`V2b }g8gA|υ (eFL uXsq}; V ˈy$=C' :V0 *2Wߏuss~aDoZmm&rNb߁""LK uUZi=&f^a2p"#P?"PJ3)+fj<wExsU_RŋNHbnG̈[6 >M}+Vntm-z^_{ |%Kﵗk/^u~Yg_uY>P)^m  (0) J3,հZ+2^GqQtlmI)(K]Dz5+Nis5<R#T+rU?$t=LRR0Ws~/34d <8/r:gP( \rgQJ<)HHn}VTRkh'r.yO^+cs<{ Vb3ȳuyVJU0<u;2N)6Su3+S꧄x /۳OgWgݏͰts[o>zHv盟=WF*dk!]XJ2Kn3tX@?Է>0_=&s`xFS>f)OY#$H#!#UN|asB%VG5E&7qRζ?v>hPAO7W ٪> stream xW[o6~ Ї*um"KblIr,J h>2sM ndp6`M%s!,9C}ѧy@J\wyW7ċ3;%%3)1h|DPWHP__/D>%8)@ 2Ҥ%{i.XJ&82 /:/t?D?ƒH[/npsO8I7O˹-CcC+o̴rgi9+w㎻uiyctުJ(Tu,`m' V*:&mLU.H%,!xԘ\1ψSu-6M%8fku5k_vZޅ1=r:}jVxնܚun 0Ţ*YY~YT`mov2UWǠS;HE4ͧB1#kIo=5>ζޭOhxܮ t5ء./†.ϛ|pJ@du2bn}phȰa5јC] %C ZDd_:1`P[z)V|ںQfQԥ?q^9U#+(kznkM- n[2Xo22ͷ/kڍ0AVXema#U)p^'1nj=?O5dmAAt4B{q-l~w-AIaΑgQ} T?t6p)ŁBfT)mc޿Z2Po?H endstream endobj 959 0 obj << /Length 1091 /Filter /FlateDecode >> stream xڽW[6~`3F+!Xz7a= P9XcDgq#::O eiU8a<}\|uݰk]pݵ˶埊府|^0ַ۷l }%io'Pwfbf;.ºL]ÌSQ kQ7PB[S/V(d[`Ӵԧn9W;Yh@J\=ߕ~6Z~Lkqav)+Q ŤUVh<7P27}QDT 4*`*k#"5~#E'#n.*.J ¬cHC{RA\M;ªvN.ËSgbύ>A:&23M>@y>,+h]mqa(.?F]V_E,Օ7A\yTd"%Fđcƀ<܉J{20uVC)z_%YvK) ڞi!G atlQD֑1B_&LƠt~UT:0+PFi4B0I0!CY80/cfEuz[ĊH̠vA}ryWR ܱ .!!^hvގM_kat/,Gbd~!'C|JY$&~BM݅|G!-%1p{QЇO% V@-JFX/hDD0Xqy2W84YCj[?bF9tVeol4i$YfǿHϞ endstream endobj 979 0 obj << /Length 1117 /Filter /FlateDecode >> stream xڵWYoF~ׯ pM5vJ^T!XQk)*U;%)RWdas9ofG?MGH4p18aϨ3]:3|a$c"Ę#DEEorS]Z 蠝^}գaf)5IZ)=K##0e xg\/ǰ4_ACڎdU!ck)/Z-)*vx[)缧Нz,nlۿc/(8 "yuE]i*r) p-^$| @@A"Uzڽ8e]"_*= -(iPl(%)E k(SYYq1vw/e&t6{q0JVWRKt{3y1WZAG0h&<3OE+;~)I0DNfs,a!&"Os4s8D^Sn$B& V8/PDE X@.WŘn\`w2 #7+*8oST'j%<-oT..ơ[f[tMkce4l3fm1q .hKe@'$ uAb7l8G Us}lm{UA7ζ endstream endobj 999 0 obj << /Length 691 /Filter /FlateDecode >> stream xݖMS0P{^-H?`C;$"CbꄖŲ+R(3p2^} %SBQfA,X5]F)d4!gij:|t[$e` 2v6Q=ahR9ϓsJ&'[HA@&xk@ʡFAKF 1bLA՛`/[Nՙ0e9W4]U~-= ,@S q9$j}x՜)J[]P5H4\Va>;W7j Y n$(E&i#c*uʃ5˞PzJ:hҌ*#:OKs=gB'2Pƻ^SUM!, J{ߦ0Jؖޞ8~լx7\Z)A^X.of8ֵ 3)A*cn/Buh:?0)NbXa'cUKZE! CqRC5 D=7X+nʪV3\ ,V6iKfyZ^ߺflO7Ѕ|j?<6e q_}a_ƩՋ>A6u ;u5N&)Ex| endstream endobj 1015 0 obj << /Length 1005 /Filter /FlateDecode >> stream xVK6Wȡb%6$@N/2m%GכZ-83#qp""Z"1b\D(c4Z,7&81kZ;ïٗ7N1*(3md6℠3jhp~`$8rL!>SꌞId1BTORoz&`$6!!q>=QMUj {0BQ i<hmBXwR7ʼn_pș;Mlw$d >?'6i ?Ef!$>H)C2T+q]zyv^{tG}cU&6Y^U1.QA9[)1β3cO~ݻ請(dzl6 c!^~υ5{X壥p]otX>J1掐-9K5ߡ7ÄLsy͛c|pn9{/WTS/DyѷaJܳ:eeB=\چ_ʍT믞UBj xk폃q <N{x[3TNΑ3T"*5m U]{ϐ'O g"s_.PU&(Un?\" ąYCe3Kk1 sǽx98 HxWr$p,,E '@z7TMՇ+}m kUnm`t);aDdaVz6xe8WڑMv9躶sބЎ+fza"_WZ+=5ؐĜ#Gfƴڔ{n%)ܧ!Dd6^la0K"lA3ԅ3{wK,Fܵ*0U?l3hnV endstream endobj 919 0 obj << /Type /ObjStm /N 100 /First 888 /Length 1819 /Filter /FlateDecode >> stream xYMoIWqEݍ8bl$ɄaW=5ocF4WCtjWljťd5Z\f\r%&qW]FSrJv }AmR\LRhcЈ2$6)4\ -9bR $@I ceLUJX&.b I .EcS"&b6։1aHrc1؞V #&>Ra8pCI2L r Ae13vZGJTx,b1+l(&ؕdӗlVI HabV`6l`rD OنVH8i-Ƃj$H+H5 d1 KZ+&$ vl8.*9 k1x_tR!،P$&+&#'17c&uW<{+:ɱ328I1υsI)Md^ =D*v^ N;wFXqmZ}Y|rtWu/0Ip~`l^DZi8WݹƇ8mmqv~Qҵwh#@jhqn~ܸn&t|z=]DO'Gw %pVjKm Nýb -8% c܍ϩŰ޿ڴdz?djLG.k"4#ºd}& G-v^<{#~ɣE-p5yKv.Îj:־-!KEd{3$!jp%F'H9_/p8do5/'d+<)xv+JNyi4Jr4ZqIKr۸D]9O]9O]9Oԍc(]nt[/I+HD,) Ww)˹}o٤Ts r>NΦ}qQQ\YAxJ{}S/OD(E]>3`9_ jgjqX{s*+HZ2D myO&ϝ /Z Zj} xdRRQ{UtX@컠P #i:0NfOQ*EtEm굴NVw|=cx{T+nߝ!ɭ0wQDi'*A (7)&h$B'B '`l9{8 R)7oM^ ߖzPOҭhLlQ5qۗAQB`1|:}\ cVW,4m/$پ\t%b+}Y,01K^"5Qou[pL .2<}fEQX(YgE!i)/['8 F7hW!#117g*A> Q%Q endstream endobj 1043 0 obj << /Length 1568 /Filter /FlateDecode >> stream xڽXr6}W!3:! K|\/b#H5˵ CbVײW Qax% ɹ[փe*[7Om=NxD)3- y[5CIL &1ǕznhfS)"a΅>\ GAJ8@( mJ.VסB^Olz34b:v(ffqVguePrVX^_2B@pк2X(<&^ekl .??$@aNa0v2\"m;ś4;L/l-%ЬJM}bG:(9zZ=P~>}-thf[Βػ+^ʢ@ghb,! x+)_>2[6i#!"apTu€eFFit8Nmc!Р.Đέ%**Sj:@3{ޱ.d*m<{[]8(( $=zߣ\,Ww=(bQL(r06Ws!/iV3!XIql;ě q/3N[7Tp~oV##-[27my:,J|eQGζ-KAZ.WeCϝ0l̡=_Wa(DJÎ!A9މrj,6`ݧU =64&%J:Sz!+%YpI-r7~mxW G. j9QY}6zPjcow옖*[K` ciW+C*jiW ,Ec۱bfC]tXJCAX<'iF g̵\*- cӷvuOesG׃g~5:3e Ͽy4`ГBjЉt endstream endobj 1091 0 obj << /Length 2012 /Filter /FlateDecode >> stream xڽYo6B( }Xz\Kn ys Zfbup%9C)K$aXF3Ù<8]@_f?\Ͼ9AJ҈EmRJ8Dr\o<_9Rr\zˬPmkgldįkX2IWE[>??yC`$)WEmκcGUL$t_px$\֖БɹwHݶ6HWnTua4$!޸ex@%!zgt$!Hs߿ydA$#Nt(L ~l9M%,' TF`@.= %_cɕ*ub1dnEGprȻ'{Ӑ0.u(D'U ݞH_Y"'$pN˫b)){u}lKU7ȱiY'{:^:a_$8 +gl%$}Ֆ\DHI]^M3a%!d*LSb}QwP9pKI\y*NU^^re趵ļT]g0kmؾDZŸ"n FW-zQvH9y[`u}uQHh;Aw ORVYnMuġ@pz"#1'hmiWi`D>&-eH(ЎL#1LJRk69ػ@htV7A08{&gXat'&癁 62yt7HQk.Kcrpq*z X$9@YT츚W`e{/\]C㥼8f% by]hD1\pUn ěLUHX4K>#KOܷV-u^ grlFVA-t@C߅ .g!61)P/O y( =0k6.8\1._( i\Ek` HPFpx3 9l8P4{ f|Pd{xz|g=<` 'K ѷj_btA@eBBWwG,,x=I[Sv+ô/<>>v4b8!V)PܻGe*b>0C{ϛ`Hj.2ac7E,c߀:/yT+{ZGB8ToQ٧G wMm,R*gN1:;E6Sg3mfoyGl:}1>$Kǩw8^614cW|7:P:+4Ja ߕZjK??~;H "*FN<Ν{i.a,XNcoxG~qɬ?"0v~5@a= ν?Ȍ! x?/p}%!?)KC~yf/Z`~Vz7/F endstream endobj 1123 0 obj << /Length 1484 /Filter /FlateDecode >> stream xWYoF~ p7yH@h䡎ZRK*^ISݙon-"|wrM¢ e""#eH<::C*fyګóU JRka`?LqDvL(Gm_4''@3h/Hr%8E =!:D2OQ qS7pH1-JVI'"DiZYmU] $I4IH^`e/bP ( E,±wUڑ]qWR<?F" _L%bLV?Y#@IQ&Jı7w>g Jhx^KƐw:quPp!+z[rcuZTբ]ưh @n^ aa1(A`;p],kUx>;" qaTNƏHt >U7n  t30"O;HѬs'O&L Á6q\.QeG2`.|F<6]60.#&x0&;| kUc'uܑ܀wnתY[ڈq^+2+H"gvĶPZ9́v[Rĥh)t{K\Sͽ\5 *iu,ԅOS؃V_l#ƴ ?rV2Ƅ17im-$F=G' wu4/4x3dg;^ſٷO@JG":Y"PdRדV)boca) ic<ljOdOalPI1ͽUK lUS% 2|v .LwRxz{e4(soBPd(ICb,# 6xTFIv[pj}vXWZO9'AY3 #:-(4i¿N8<*ӑ җ B (֦++m*fڕvb[ٴnno8DBQI 2iG*VvvO6Il 5 v[Ͷ*#-mmD3(X֠\>T> stream xZMoW\8*׆^da;JdWYiIn-V.V bՑgs-3\U.VR!U5e @.e)]qqP՘RrRj-6U;Xt 9]$ 5xP: ȵ*\\RdKQqn1apHAj:#&N #*&RQc%u}+ k5XQ@iAG0Ӹt&1 ">ˆ\\ C=}RBl.jNU".qjF9lI;O3KaWci:[+e[ߪľ-I˜¿u*Nu6(4;-5PvHK:j4KRw2YbLH᷒>*;8z}wmɾak&jӔ)&Ӵ3L4ċEce/aK4ϒk?^ݣGn Oۇ=C` QH L q`OW?l߾ݹ[[wy_} 0l;}γՋn{{v;T۟yأL|њK[=?4 D 2M Մ_O}zyf߿?榣W^eWdQl2do&cdL_+1~%ƯĘ[QŘ[1Vcn,\r1,W\r5,W\r5˵"Xphz+`OFq@46ZB"asZv36T|qD)Bz ZJ ቨ1": d1"zD21$ QbDtE1":gQ"j`Y @D*D42U%=` 5ϷX1ouЏ0Q N2#Z9GI8nޭoן67s:xVT.$AO'zXлIʄQF UtA1Γ5Y^=Lsef LhzED}q=_I/L%rl3bǀ%Kh˝.9gg}gБ2@wh(hHp8N rgzcAOQQ%χ֯)zu2|`B%+␌C1Odis 6K"kg=/ endstream endobj 1143 0 obj << /Length 1068 /Filter /FlateDecode >> stream xW[o8~ϯ@Mqm >tiUՇIv_2Ɋ˶ccC0!iX4*BX9h=[к>\Qϊ@D1+ A`R% ]3H@S-/Y֫,W8 49aF_ B ̸O"ӧ{^u}׼dOd7eo<7؍i"LNδYʁgծ,'o=*ދ!i1Z  ą"Pmsщ^!]R{mw 3]D@_x1l}O݋ ZFReR}q1*ub`l+ׅK-(h;/D}oemǒd,:{PI([Q2$:I5 =7 GӋ<PD]GWy=zdm*m-]c?Z_'֢y&lnP F/'6K+>\N5V {6~r\OyYba~R \2|7sg% $a#p}=;^5b/rsg0u|DD6+pXbVy.Zf[W 靨Q(mcd\3C["h?qS E5?Wjɥbi-+M qc8WC=w0b\߾ӏńzmnz>{w}Sm7oJ-GAGD_ݳ!NIm)??g!߶HAѩm*Y)WujZZOi[zUδԡLDhAKvg6^lYYxTӥϲEQhx4g endstream endobj 1159 0 obj << /Length 1059 /Filter /FlateDecode >> stream xڵW[o6~ ҇XĐ%J!M"Hk 8,ɓd$;"u,u A@J><|"h\\ wm" -"΋"x-fNj+הb*%FE%2!+Α.d-u3U3!d^ly Y`x*qA:^ *&ngJԢm|#m1}kYM$(sc%zzwd`@]Zl" 6RZk#٫|9"Xߜs_ e?CwlKj j0tfP$(2r#WC&*i,Q߁rbτѶ=!0&加~{YI&ShMn~'ۮ_@yp9EP+>-DþG29$9 oP?WLVGb`UP@1C^s Rao8K{uǢvkE"j Dc5jwaMt3q??Z3qr']x̒cYCy}㹕!ˏY @BT3p3LXv\L JK(PwT8*Ԅ1M@{~9[jb~9o5k"˧,fVfŁ;I4;/ZdV^QݞwLE; fPʨ21,>*3J]"Ӳ8 .ZCf3OoB\hA[pxm4SB}LT ><=4etH}´y[`f6Knkc蕙^sYt |6 6;Yq>+y@>73:-7Ÿ%4yQ5A flVeVQ鍙C6Fd>$]!g'1 Y墻Ө3^1YFƯ[_dRP{OXu7N7j/;6 z 8T1pn|ɚ endstream endobj 1174 0 obj << /Length 992 /Filter /FlateDecode >> stream xڵVIo6WEH %, %ȴZj&)># goW<@19hF Np0\{Jax.p+h*S]i-\.ggѣrF%OVV,/V b0b7ma<J0)a#y]d{C $18p,i=sNnW_dvʧۘ6U$6(L:o/tN|1!:‚xMX=vUf䞲9tJ XUS]aX2A?1r5M^ZY/uݔy2wt{;壌tCMxJJ&0 =Sop0=U&ՁJѹUP5N$"/nJUН2?AD`-hYoEYG@tU,j cUd:_ƟG@nihJ7;v7Ů@Ũ%fߴť?oV gFs,}ՓwR͇01g)xj<+3oΌƮaBe#&voxfB*CEŧˏk]r]3wcCkz\HDPpCSG~ug"mHIŀ endstream endobj 1194 0 obj << /Length 867 /Filter /FlateDecode >> stream xWn0+P.(iEqrIsPlz)d˵EYfWN9ff)9)|QB0|$}gh8F7a$|?^eP,YReL[VuscIκ\%TWWNQ6YY\'߉ =J_]AHc Y"cE;= 7Q><s-=vxFݲ8ңMtT''qYԂmq} WE; ;@S%D~˵xf|,nM?:;_@`T^٭UƳv1С.f;Dxs^l&{ϑPIW5idY@ Ί 8|%ʍm/>oz}D?]7h PM endstream endobj 1205 0 obj << /Length 1072 /Filter /FlateDecode >> stream xWK6Wȡ6|Jb:hXYo.IZʲk!"'Qpqpv|0,H4櫈`$H0͗ч!ţO?&-$A0N7UH iK|41sn0"x>nUYɌi4&)\:EԢoHvwZT}8&1|SyQ00sEimdXf[&wX.|WjU~4"o"{j̔K78x(uC9cDŽ )b|`*Ոq_ B|~_9j%"T䥈 ^c}gziC=;ҍk!XBL yX_@MCথa}Iw"~våZndǢeEh?NZvީ~UJ3 6 XZUGZUo86teD>Bzlt6wPY CW#ƴS}b\ L4WaD'-ar1FVtqĒƇ~bN"1> stream xڭVIo@WK07*ZԪB.P!7F^Zi͖xIijy{7Oћy)J#y;`8(dԛν(/sQuyֿ^99&(N@:AacdiO60>O8+9y> stream xڽn6_!/2P"ET=[ZNA[,y,Ëq'͊=ߔ8Xqq|K e:qb&$8/6e%"kREE+b'| Nሃb=.?pƐ14?'~ИA8F*ֵz:_JO?{ -(yD,G=+=iT^^W':8\;N㑻}zر׿,OM'OPQ_*jWmΝ~J  vgw6i8~[:6Tv)v.7A'WF#{C7pHLRĹK/j7gF`yƣJق?ۡ+{NǚpҙP)M*ԏpΠ|X> 9t}o=a{aw sȿ}96 њ|Af&T箃,TU=ڮ[뫡n6҅sZKț󲴧WVc5#YrDӢ}ɔQ P匄y=g4}oR_1:)A9ׯ]޺y7+e٫*BWckBiSj * ;_#*+{6ƾ_0.͎rdw P㌼`L V\|Hn݈%^,F.׃dH@8t;jD-|O苧*򢗮_\42c[b1u]ttanqU;ԥ% p '8Qgq{VRו]ݴnqOZXh ;\scIhTU E??SD.᳃BD?nJ6JvFsd"]crcOoVư=/2O<¡46<ޞz%B@}MT F(_Cp|J~5nvj!Ȯ*j΄Z#NooMK7]t=b>,EJE6i`Rꂀw$/)[bh=r!ӓZ T i|ejK Q#8Ca| PSvo `[ouiklN)*§JT8y2)Jm-:޵8w-r!BgȌh*  }&BzϏ͚ endstream endobj 1137 0 obj << /Type /ObjStm /N 100 /First 967 /Length 1674 /Filter /FlateDecode >> stream xY]o[7 }ϯ"KII@Pmn@7I%yphk3~r8$CIQ1&vŘıگJb* x`C:a$#ؕdRX\ɲD{]ldxO(Nd8th0HNR`cɴ99 PR{Sۛ(QJJT ʹP *7cji qFEkn+kxRH&6+l'E2*X $&Pj0`@&s3⒤.)&$M)qTlm*,[mcFeVU`T p8S dku,P>,VsjqXر a9SC,P@xI0L g"'lqDvq(m q`%XoqX&qI`uQD BP5DL*HUßU)7|EZdBX3eK'(ix'8FЂhh ~O$Y~7Ǐ{O܂ 2~1@(^`ᵫ A.^Wbn 7x}}7x|f78fY7[Ԡ|4|6^HO:B\t<@Y.=eoptvޞ_&nڴσ_Ϗc{0C0ENW=(+9pOa~8|7ݻlGn#Q ӂ\\Vk^ vӃ|;SP=!8XZG/n7eg~դᵶϹoC:t\~hKLM|Bǭyy#o$ͼξyyTNBW(iI%LNl>0wGbO[cpY )PyO-QkK*,[ y9~ء5Aݵ?7yk9n3ndCKJN'$"zO1r>b3Qw9*;TUH>GcG :a% oǒ~M=hDn2L9v; hFkhdt>]eiNwUrm3_> G,Kꉖ ChސK/jz?t'PK.wь*C-ŭn(nn w)uS9`1$ QЩ M8,({c,ŞwXolP+xأ kG!=4.w{Jhx{EGAZ$ѫ}ݴmDϽW[ҧ#VWB|O4vn"yAN z^q9< Ům;}?uLWOWP9˛S.I\|.'Í!m@^875#EGB֞hX(h%GFCWvRR鉦POt,~Ry`K.uB1?BKS+W.$UlՃzKDiND O}mSp:\{s<>]t& endstream endobj 1270 0 obj << /Length 718 /Filter /FlateDecode >> stream xWAo0+,D*;tY[*-)끂P030v E?6@[g 0/Fʀt,&3yGbEj_]aqZpHB<:Dp(DDpc-k_ ^@D nۚ<0b!"xlAv8EƓayZhKT/O&51ԟ ämR91mEe79W WR ԃq! kA̛ޫ`%{9s瓓"4#5`J:@睢pKҙBq0XBN!(3 $Pn$;rY,P? @㑐+UYQiXIbDyc.LTK_")2 .4.d}5exyC'2]QgPإ=GUuk6Ѫ|T!N8*^O2}j `oW4\y2?=V߇k5m@|] MQ<[Fq8${.!fS:2D\o"Y:5-xcuO1t~B ZXjVNL?<> stream xYMs8WhԊS6M:!qزMA N:2ߏRcr'^DqrR#Z ? 䧟y(ub^ C_8~o+QGɰ+FB=D ! Us^8#TkFi~-۾V%кBlC?j0 t[- ݱ@8 nO) \P$f,ӣjiϘ̇YpU}/$M$7z؜`<tSlߞ{i{V&╞@kh*rՅ S'y*2+<]fPӈNƼϹ6RUOUv4˾68=c>eEM\Ϟü2vsioJ 2,e=(eҧX蠫\EG]zTׯsYH`I(BT%:*ϱb%. y!Q OUa涯sq޵ XheN@`3λp"@ cH@1SOWbl\ i['E`v1mX<|Kj+Rr+W׿jx);a՛/]=C|%k!jCvǰX K=B uɚӾouƆɲM|"s rqܱdDB XЛ GLiu[p58m, c 2`]Ȑ^.^g*! tdÏ"!:vH{(@eG"-"|D}rvRM;8bW `WU.d kih`S8U[ ؇)N??M/c$I[{aL槃 jı4K&bYw|Li&䜳]ZXOAS[d}tnɌAuFˬ|h£WȬgrhoI$^GfB>!T]IGEhrBe1/|mƭ 7Sԙ+.('y id endstream endobj 1304 0 obj << /Length 643 /Filter /FlateDecode >> stream xڵTr@S:*38(*.S)˹8>H"fQX30 2񞋦ݏ^O7kp} B "b0B2| ,ҝmTt3M'Ǣ~<›Y 痃uƁ J+ Яܶ)`X2;vxg˞>{`cwZ?#0 pcg˸L&Speq-G?gyIkGՊ mU 2 h`8~ReTkGĤ3E&pu4rmKɳqQ }% !xT@Z*\Q 5 v?G119Wu!?u`RD'1 vQѶNUV}de{BE !6i4$Lj %2hʑk"|(|Q<8=Ѐ:jFD=8w(d^2rJ{c Hy4 WyajcAme!N:;??=T(}hOeU`CQIDyybs'KYv%<{Gg|+sh* <υ[Ϧѿ,M :ژHڗmKޤQt endstream endobj 1318 0 obj << /Length 928 /Filter /FlateDecode >> stream xڽVn0+P nZ4M E%AiDžeZ;\$k H D{3o$h0z7^I,CQB0!Bdn,&O/%g?3"HD0i$44ŏd Jq$8Wz&BPCAQDcriua7>Y@ת=9)B)0w fSv" $&E^|P.uÖK71$vۿTe\ϳ, 7$mI?sPr;* k5vy1>@Rء2*8Q6,(i FE'kWt&u6_.EމKD!a؎Wr[-Ww"n}$ٶ/[y%V{γ+;{sREYGykƃSojc,q̃}{<km5^Md7obʙEr!Ы=(_zmPMśf{84EOY @ @T)XzDQG6G|| M=,qd&֏.W=ט['vqiژi=:4<ƣV>J:7.iVfp;Kvqr-9چ[m׀*=hKwCC'~ 0 endstream endobj 1333 0 obj << /Length 1225 /Filter /FlateDecode >> stream xWKs6WHX0AuN:6r{Hs@HHbM. Fv}wIYq,M;`v~ڡΏ$t2A,WO) IbJX8^K:ӟ"OxcD}p$2 Fs<-dx~Ec ?#A?a$&YX[<`ԕ;%XЕM+Ax>sZѡT˶\撹R}U%ao 0n-ʿEE긓I ۲&#^MW}!Z+ȋF !!7q4vZKc%xgrS-[^>2ݕU]R*7fdsu>r3`Y.ŭ(k6E D&BX^7EC_ZDjh2eBꤸ oB ctt`hulFǍ! )}\jZⲬ׏n](terj0]gQD6zl[!7M@wik<(,^ lٶ׋I7O>"q!! HdVzrW7Cc`2'>|NQHNn%BW/_lQNM)#a:%I&uh d:+FiF?_$!XBRT -U:%%. ʆ4U~4~Ȃ,Wm5F`k ePFYG)sע ~[G}Ir#& 0\ɰ5hAe}IVsSa39T}RʻZSt=;.RxjwzߊA|#[b0qz{OAsA 1>0rIA˯GLWXNu}w2ETAS?@Όibu#;IlrE!v{L9:#S2eQp4 || 8u"8i~lY6?L1!˖(2'll%#fTew\+ 㽊0+K:*CO>#IlKYZH1p )_lzJn:Pk/d`567ҤE=|VnmN}|B")qH > stream xYKo7W^$#hp[  ;u8!E %9vNVi5qb\%+B br"љxX(1b|2P!/@xǩ.NHsQN e,LBAPpUz BTl9AHdҩAAftbH r0ANu 0: A:C@:3ā!P !TB( @HbݎGd΀ġ_cN NR xgbcPc@4_}(j5UJ=\l0D cdG@Q( bP*lRY)uYZy:tUV AE6J4)na,ITqvbz< (CT|pԦCPP=(Ǡ``_g`ݤ8guTN uv C t0@%uZ`|K EAsuR&8FfF{{WiN9~/'wl~Ώ\ޝ646Ϗ}}5, S,@ 8u)4?^LpN\O߾}8qѝ5ip=]\U>O.y 9/O4O7>\'{OV?v>9z"+J#h5ng18'xăxNs[]/,aXqn:fEɅDa*ʯ+jE^.۳v#x1X%[ cD\Zmr%5|^=r̦QP, ?)i$ O֡X_S3?v-3و`z}yy ;BCvfFIHЩw{DGf9)G,Fg=շ8OT?.I@KQPg'7f}T X9ΎZi^uaiNz5PPw:TZ̮HHj'gbYRL9Ѯ$m_J,(c5jLS2lu^Kh8WtW6* h ,IvfE}GG!h hbO>=o;W1RoG_+!ʚ(nC 6 s9á^e Wֻ  X=`bduB֫%N\q \n ɐC>3|+Z,u$8B"9[5|6J_;8. 6]P= EPgKOߤO+ jk{6gx'Z֦i#pߔ~^4#殮}"EIOtgKuI2:=٩N0TvT|{ooU6a%$bүRVcZ1Qfy{XNFE2/o?dr SUu\w4D'Ro=ё+ !NЎ_q"] ~}'%h' CU;jGEQd=qe o}dR?į/~H7?]\^࠰E ]h]7?htPP=~Sߵ5';n7~Z endstream endobj 1355 0 obj << /Length 1189 /Filter /FlateDecode >> stream xX[8~ϯ@JK`l;v2lrIh1:4!(1qZog,f/( XYuG.=b-&⷗oؾ$H(b`yU +QLfn|=MSuӓkx  @#D 3SZB;YG.+3puվ.x.r3TLs"Ass#Lp٪vs)Veg,#i6/&m"ViY  QF&0` B.[%Ъ^kUJT#pI$^J?Oݾ#Hy b5#7mDߵ/3Y՝ F96m x}Sdz4IJ%r;=h<=p_a78(aŃJ#vZoد8n"Hgnv}ྱVn߻V64UuH ̺4҂v@E Oix=fkmӷE }uBkIz8e2)Dx^BUmz3TcÖC30䐀06I]5&VVl T!DtOҺ{P=Zx\vwW+Wb&QL VrվKmnx]@S:h3u Ui~+x;ܲ.43mb’~?Z~-VcEߦvYGoig0ypBz{fmMgImF;J_''4h+|:baxj*7`X8\xH{t endstream endobj 1377 0 obj << /Length 1057 /Filter /FlateDecode >> stream xڭWr8+ToXTR35{6^ p:sF~I:-FFBV8-z lf)z2KJ*zG_4wAm+pɉŒVPѿ#;[P~`=8B/y6\gh:l\+6F!ЊbmW:;P3XqdN]„9v|lhQ(׍ws$Ql[һ<)٦bZsj眖0;BcǶ\gg{l”YN'Kz!'=kG9 },l7\Wi>iKn}//buF>)'U~}Y1uYA.inS~^ mQh^t9-Y"O~/bN2maz{tO<$/l'ʌlkAŦ]NJE{X5Ek0IqZI֒yVZvLhI XV-ER9{vθ0^]Le ȚLB%dIu[AIrPs_ #f03qcG2D.%+ؾ*WE&Z} y:BL5XU5 8/|WR4GS$ƞHXnjd5=.9QgE\vxF^h8p/!NMIƋs˘k-$J:Wc+tj^l DzsZVo4W7PpD{m|2 c|>Ҋ:Z,{>tvYݥ,Q Gy=tFP endstream endobj 1395 0 obj << /Length 796 /Filter /FlateDecode >> stream xV]o0}WXt66U֤{ɢf0?NiR'8{ p;{!1C?ARq&cG0 ߙ%xZȄ*qZgIwUJhpC߷0(H g2E 䆐" ` Y@:#~km"[gy0 "7->#6C*n:JAY6 Jor-֧~ >"5LJb$H%ِZ/xxAWKg@)s>oMc!#oLge4< ZCCFGeSHPBP*)df" ZUceާyzsߜgVǝb#2)ӐRM=6,>TV7*10yDuW,o\lp;M[ѮXdk-~9Bky<]]5_>k|!\t{mK0&]*V.Q|e1d,4voz endstream endobj 1417 0 obj << /Length 1232 /Filter /FlateDecode >> stream xXK6WCm !"mhuCMJeˑwHJ(hhk8~[zitt{/'{ӅG0F,zӹa|TTv*&$"i"#\r{-YEL TGܿym60'0B,sW}nCw/_╦(#z$NoNo'2?VH2m#G4j!AE>!xܭզ,̻ώ"!8qHFvpvs^ BSm-8R3+W*˵*W|YGlo\% yaoH RoeͅBB=OILqa=\Y8!X"J&EA:Yn_-X ڌW}`0fS?Y|q)M4R,d:o)nNuB'1{{" D-*(J@m}66Ѹ~C"ACbQ1ODPaH dw9$ϒI/P(*! djS K.s-,_reK (qZV,>~;M>r3M XڟBHh3B!,Y>!A(؊4Dҷ!.۴SE—Mv ;eS$!ifT:!Z]Nm` Mfe4?oL!Ú SM!*gHe d7VmokԞ,+#KQRe<,S,e_m%dl2e8ݩmein;9)/j:u"NAUHL܇E`jq:2"F i*fч؛K dD^Dzzfjs͂c4r~vjk!+BuOq$ :Sf˛CcxG! ^EjeĠҘP,OGչ- QŠŎ:0;Qo`pKpn^VϽ;=>fצ1֋&*Ɔߜh]6֡N fqJw+J=J$AعyB!A5'XҰű\M2a;PH^ endstream endobj 1438 0 obj << /Length 806 /Filter /FlateDecode >> stream xVn0+P17bzJӦ@hV*H%E5v"4EμyyC&ϝNJ0@ *`@R`E2 {Wrs'cN2I: Qw2׋2)gžڛqE7 J\Қ(w&@XfY>*6#TLq!;<[ 0r7g.S]wiLGn~ݘal'ӬY9͵nܥ8Кbh !"uFu.'BH  ?Bfn9ρNS RH$" N@z-OBnThjpNcѷz~%ak1^b1) ]{1+]Na>,<= +ެ|<.[#0&@ | &R$>d~ܞq[.be>g\9òi!/s`Bp޹hd>^(L:GZLQmVMOyTc 1!mRz&f9_]kQԣG6nf_+6t0z-k9Ja>{{d9O'-y+ڕE Q$}3G3#ևR>s-7TN{!\} xɾ=qe ;d+$B3nhE/-n'Q\@Jq8niqo_gޛ1S}:M.?s˒ֲ^&]v endstream endobj 1365 0 obj << /Type /ObjStm /N 100 /First 981 /Length 2058 /Filter /FlateDecode >> stream xZ]o[}cB  d].hkAk+P[ ,=CDUre/fp8gxSf\L)8dBu(.S5!:lBMHJ4] )9bBg`&Sg6 %eH9: (F)GᬎxBT*@GBIp j] a ;͈֡b*RԄ%D]JY)k$ѬhpIP*=#ǡ88R -ss-B%Kd.JK8ձS2s%U3VųZkeCπm`)"fR2$p"He$\ΡaKwRڻI&N4sP')48a$[BԤh&HNc2,%`j6@` Sp-f"j &d`,J UBvZB0i{#YFRW:NՕh98-.. VQa, +-)V6[J vЯ8lV--4Im7iF6#*ŋ?r-+gjyw5[m¿=yv=]<5{d }`FX,arS=hS=6'V..pr څ҅n9w˹[~ɛ_>ݵw?O~s]"1|` 9EXz 7y&Z]k rG H@$Ea-H _\/ohx+ Pt/u3]Cĩ"1xQ3_#)F=jkfOV"^PcW! ёM:u$B;z~;:" J:(l5~Ra]yTUCxngwfcAB7%Ǜzݤu:PxSs{uj6:84Y.Q~+˻zĢ:bHbVo7% ,gBE"B?GƶSdLS+-`lr7^fp5>0 ^77*GBfti0aڠh2*0mnBteeކڈ&Lq tzv bԸ9f\6Ƣ†qtAǻb} <5a" gK1u#c:`j Nh6Xqʜ:ڎY}?m폛͟0on 7on{XQKp?2 SR6:* }F*I]|LSj_[A](]Rb R lizJ'x,WFzMog#6)).dT`_u`yy3FIDGQYYbwE fCPNr |Dv(#~ƃP>t=_.<£qpF@P3~>cwC 0QU ч-q+8>[1f]f.~9+J$㙴˴B!k`.Dyafju}P@MV6Y^|]? ǝ&#;1T>gRII΀Rg@sOqCA:a{E7~2 b#]$e`#c僃3B(hgtD>r=uvB[b& @투Ƕ Ԓ endstream endobj 1451 0 obj << /Length 608 /Filter /FlateDecode >> stream xo0WXDnv#6ccHS5~{ ;f$qƭ)cI<ٵRnF7,H@)"edjpRc:mד3d@,lB$]G@#1\192WJִ@QF>GZo{ma A1A}yE Q@Ixǃ2pR1V65sitܼċI(n?B06jvʹbĩ0($ñP[0ZiUvW%CwG4]8'PLR0s/F{sm_9^ >P[\̛e{yR0^vLAXg:zZ}k~[2}],[: }XIV>Eᡍq"⎩]ۿ+;X)JX?S*K䃽W!y^;$c;5~Onܔҙ x/ B.|N}@J^Q`N3VK?H endstream endobj 1465 0 obj << /Length 1901 /Filter /FlateDecode >> stream xڥXmo6_aj5#QC!͜CahX,zYd!@L#C93哳Л$" e8Y&'Qe68_.y"1:V~Zois8٥&='QO2B!BuE4 \lwImFyvDxInIEHbi۵gsu'5Φ 7ϋ nWӺi߂?ʲ7ȿ$jX˙(vӪ6&E 1fj 2p| ܫj-O?8ݞ7p0?L9z w&H_(B[T[| 7jyM%bٕodjArX :pKoq!ΫYu K>9~ @=7weWT0WRi&iMWSx(#ULEd皦ݮ"1i#HnF7m DKҪBW.~p7"_lebȿ*s`Ǟ8u–Ϡ*w-ja {Tj?(opaoT[  Rs0ۜYn!+ӮP<v@whu}vsxԾ-#(JxC͗ŝF1cP 9䓭O!8pa@Rʟ#qHx&\[z1gm2Ѫy.5ʁC駹oZ(.JYQv wIߵ\{<+:{Nk <%#1Uuӟ6;t#;.P15d ?j{ՇM8(0wcĒUmHNXG%(Ceb $b?;K endstream endobj 1475 0 obj << /Length 1016 /Filter /FlateDecode >> stream xWK6WCm Hv] $qrAGa[$g#-YWm`Ip曙cfobB)`.Ҋ`OpQ)&c\}cW-&_rIrIB~~|&l쾵ݤT{YI8tR,|N`%qǖRoًǕ+ϧv2`Y#M䏴iuS82w((XX?Y6d8ۮ̧ܺ{Ȼ)Vk̳^6A0Brܾ⻇>^CTREǤ)ӝ, 'iO)60V_ƭ)L WL˥e{Ҿx趏Gú1 86! ļ#./ܪQ ×K2dyXfUPxB$5c ]Uu7phFmØÛ7sf b="fВ8x"Yly/%~`*Ӕ ekWt#&5Ł@[-2<nεOZ?,˭ƛDž˄ |W`o`LfeSk5!$ zҧEaU(z*4&vYy{D> stream xVo0~_҇%pm MC%* N 5DMy|[.{G X N5Xc8F̡(oG?/xxWgɵ#-ͼn:P"ǝڜ6p B򴼔<4YJ^[H@Ct uiܜ<"2ڔn&&a`Tz\@үIViPj);k(TTm uD-+ZdWpe5t핥5O'4){pڥc,,ҴiD=R`%b,QNԲO», 1^a i*A Hge 2fV me {8}=Cuw/I\ǹ:Kx߈uheކ 8GkЯLr_V| endstream endobj 1515 0 obj << /Length 1012 /Filter /FlateDecode >> stream xڽWo6~_AouhKS L,ٓvw%YRTͺ"@xwmA׳ߖs͑F1kD \(3\K)|U gHsӫ z1̙Dq:|| їzkCX{"DJi"'O^t* =8ϰ iK0Irkr ECoP+$F!X)ðP}V5&MDWIUaRyr(}60 4DFype> )0gbj!D'ӨIq2ƏitQ<%Ke>QxqT IS/>TzU,'Y5t+|es_JWVPA%)>Oʯp$ަwAjWQ)5be>1†U ceO 7͵Xllf(["``?0b㎬њ& ɹ:+ͭ&mYdWQ>J}o > /hE?*i8w~(L7,jճ _6.tWnx͛di+7feqt6-vԺ o-1áhrʮz DT LOr2wFi.{dca_t=V1o;ߤx{G8Ff~E}L3XNxq,"qipصgq/ng'N AJ'J;[\!SCF3+wigF]|m \xhwm˺=hW:5d·7gܦ::1Cy\0{>a0-@S86C۪i=y6,S[n+'׽( JsK`;n=xw>N5~A1sz* 烸aŶꢏG+Y蟂#3 @W1* I endstream endobj 1532 0 obj << /Length 934 /Filter /FlateDecode >> stream xWIO1WġDK U$@-)aH&* L}gdHR)6'@ # ` F8>d3<=$)^K<|gYށGhj ^*[EԮ7ףU:Ax=_(m_$2@~`eo .*|QĔ/pԇpBhcD]R$~.L"t9N:qeo`fxw`i[Dld. ,s.D!D.ĩDI mewId(4GOrx`8ddV~MM;GFX̞F\x\}쇜P Ԕ3HAVdkdH U5eclyͬF'6I`z (ᴰQ+Z \ =Ȅ L7{A7H>>I-1K``4eۨ؂B0zė| [L)%K6CF -+vg}O&E $/.aw8H S#NtpK-mks W9nJ.S.ҎK:FYm'E'Cz\lɏFIQ+~ۺgnV0~$]9eĎX`ضn8#naxAR˭Ed64/_}?v35[Zp$T5ZW8q =R!uLlY %Zg6Jͫab;轄!]՛@AnϷ'S#Z~@5XxchizpR_a:%ddѫٌDgOMSU<%3 \s]FW(i#"K endstream endobj 1566 0 obj << /Length 918 /Filter /FlateDecode >> stream xW]oH}+-He:ìmVC6n_hEa8 8I}/ !CCẀg Z"1<lShv(! "Xrf 4Ie}g/OA(!XkvrSo %Atk %vfg:EgwkSHCCwaM 'usY?`xQpW6M:OW6#VFbDŽ܄@fRX632.*YAEC kmw jKLa!3vЅ.3ws?xg]3[]n}*"N Jo7KW'vS=;PCf*b#eWh$wE!mrټ*i8Cw{KV3b |p%,߇X)yh[]cj1}ü(]uKra&̘ 5wCp==Vl4-W#6u|A;p$,곯>nbWWf4\K_G 23b/׭9iޕ%ۊlPnxw!#s0(5ЧÄ[GcZbiRUQL^ɗ(Nmy 0xU+z}Yokx44x=)9(+9zOF9z#طL:h9$|+BZ P~o-!q/-Br~R}/F_z endstream endobj 1448 0 obj << /Type /ObjStm /N 100 /First 975 /Length 1672 /Filter /FlateDecode >> stream xYKo7W^(r3CF<@Q5|PmpX-ɿ76k)XDzC.Ґ3;orsa )"@$>A g D %U'$I} RdKiAZƌ` ;BN3,) ΡSP T3V b i"+6 2^#K_]Y o`x. ܜM lNO +X)ބT\sPkks`[[a_CjIN*9#>WB}NSrALB, kZ9SPX!B\ePTvK~!k@ЅUX5BT%Z@xQ&p(U1V'O&W2az8 W|վA(QwO[C!AĔf ]~PA-;*D%5 =~ ͌n/RH|Sː c%.Ǣ&pAWxG8RWڝ*=74ZuyUZr<&3!Uٌ͐e6ݪ~m8g m_w'3×3B5YFQ/Z'u@Tq (br3GX!zmZy̲llB{wIGhTA<|<肔%VƢJcѤzrn+:Wd'3}՛`u-yRPxK$R@ D"CȰVhN"7U*>ӏq$ endstream endobj 1590 0 obj << /Length 1202 /Filter /FlateDecode >> stream xXo6~_!fKR$%vOY+0lk}PlѠ$'(ɢ,˶ܧ 0}wί7H$!# q:ˍ3]qXx ZK|RZhgs'[.x~#3 A'pE~3_._\LO amBy=8JK2R3!okeNu1OZ%:*QLq҅[g1R(&Q@Z>!}]aQO%}Оߎ tIKeZty52p, U\0$#+QV]. мZ1ʉj]A_J.iNf/??'Z8 bg0vng?Mٖ@dC$'ӱ[)i-*- Ǖ2tK< &Sj .1T#:P8/QWH9+[\X+EO ҩ^+hT|2fsy}n^#zVǷm!XsI[G<{!! BL7 Ƀ$ۀxg jJy#6iT0Hs\a:wI͂C7q7HD|_S7M dYD}ҬjYLM1ի1zkZ*3hm))Wt]O!I.fAYk<3!I^}U 2lU-^1a嚘] ɲe m7w^۫SZ}=.E2A?0aKw,$x4h4Y쿅j ^>7tܩ܌F"G/ ңK)U Kbm^F|+UK[^T؉d4?u2f~JEԥ8.9 ȳBA0 ףSC>5y視>TZ):K9~TM.g^@ /~י|u9Pg2> stream xڭW[o6~ !)Rd[S`( q"ӎ$I)J!i\sG5"VHaW} ,|K. <*g?oN(! q@d='1i֪-.Egx}9 asJҵ'~q)6Q.{cty`%˾eo"|b6ϞYRA<[UcӴcC 6FlXyXu, /Μh&ޮGC-l9h-RY:/Od-LVΏW[n ['&DD`}o&{4c_ɊnE BP& 6moV{ &ڻjRv2BZ7L}>τL~hf_dZ elcKLPrG"Γ]i/df$>qAOW8V0Ϸ"Z)nХj1se\iT8m9X&V"s6w10<ǣ\aX oJ>p [8=4jy|8ι dVrDCQ=ʈk Rÿ:.{A%&6gMtGTMU3j6k@:OϏKSESRʬfz37\oU/AT瞝&۞Za*L5u1ܽ iSW6GL-]!!RodGXR5 +@arhIwu!՗o?ERJ( ;͡c#[ˍ4}##m㾀MЭbP<7osWO&z'6N9.NK> stream xڽX[o6~]bkE5^`Sl ˩$'!)ʦ8[":<\(-">jBH!%>Gcĸ`4G1w.]JR<>flkt^WC?­W/#Kl5^hEFѽ\Ep"ٱ?j$JD'˒8E*%2K"wT$c5j’vY9w7h>VؠgŌLJZY6 l=bMgSw>[&:2/Nue4W-$/{t\rYխZI #tHّTP!61q`A2',#$!y6ҷE6+]6XpR#,#Dkxb/{eFjBx1n <*E5_>Q{^|LM&t\gM'VL$i {GI丹7\Dž.%"~m-f'i6Mu j[\൯$f!BEF`bkRZ3 Jy}]jVpkuγFa-`U_M J 㽸 ~Cv(+'1#Z>{XOweFuqLI"$z*4[fU6kty ֕G!>"  "XbŞ8﮵A@) UvѤQz|·@+#=|X 1>Y`ЮH"8׃9RХniꎙOJK{>ϛ)X @k]vs(Tuai`6G~ءvƽ<^@ɶ{y@pawޱImx)AMD[~KU`Zŝ˦ŗ|zNvϖ|2WZg˖ [$ju}[͏ hĴZ<"\ilclsǶ13i~ܹɄ3ħ)=Q>ݓ7UT/?> stream xZao_- P$g8$\^kzHr(M]V+#iH>3oHlTrV!*d3PL QxJhwkd t?q^%Q;J2>jHPɤ' HP)A<Ip6 HR PQ)B:D삫C"Ht'UTN=0crP 8C4JP &I$m W,ŰK€1E`%adžR4\zbfDD)D05?0K@ C:j&יaE`#R['Pms8]! !>q✑P] ;]k] >Ju u\ 'm2IlRVK)TԶs mUԝTHo^ r*%HRc}FJ8xHJEcw#XtS|)D[8_)!@[Z^t9g>QQP;-PNcj2|Ng -1/;3{\G7b[:v_gN}p4;.B:` ۈEb!KC9>6f՛=78qiڧ?o9¿ ФlC {4LюSQ|^\7!FZQ6z b;Ol:D|zԳu7vwFO! ^,#!EGNA6c6iɑPp߮of L #xyuL"񼁉,a0W`f )z b<77nr,DeKlS px!3DJebysuAed^;-H"AJ}i "E[Yl `"㴉PChSc-8ZeAmcxFrǽbV~6{.ĸܸ_ʕI~+/|jxaw٫/Mqk߰?uGg-KOt_nV7nӓߺGS2HOD-jF'; 6 ;!5!7qMMMZZ*VʭT7֊CeA-#$98/VdS`6 .šeN+$l"ʏt0~͢`=J2`M`la# NHQJcCP89$!a'c`I?`C ف(0L s!=s@&:X/KD Qvtb=A>2VԍU&-2Vˬjk\W˪\|E.S.,5 KR(,5 KR(,5 ˍs[zfWT=͍.Y._>2|ȓ-N|(Ϳ3fgWx5D#b-G>ZHRg4*fȡ쁈! T(ܠ0 4 0{8n%Cr\{ҖE/ztWWS^(dxPh(vXjmx(`(c<@sYAs*>gZ o endstream endobj 1674 0 obj << /Length 1086 /Filter /FlateDecode >> stream xWmo6_Ajwž]S tf JrDQ6-ۊa2瞻xAoF#b %sPtHEч3A(b8/xe@w%At R|0B+z  >m?kBl+AQD"Ln=:OwP9|4Y2I7A$&)Wy/.ޚ¬zX~j5VfI>rq]sBHc.Mũpoj۔'-v.QgʢQ&g >"^ûD;"EJB>禼_Nn$K,Qv':R=18wNH&pkD'DV?SBƱandbfQB9 PfDcFsk{ 1V]%٪CWI(V&Ęp8F ]]7B u]~Lʭ[K”4biw !SeŬﲴh SޭIiu⪒+ffU / ;E'A @H}CneˀIn1k_xY^Y%fs5g|q-Ơ}'lJ۵EM%TQ w.ثmtuq7Do16sߣ.PBz.|*"IPGl '}^>1D*"21O[rˣnM"Uꦗۥ-F\œiZ6B9] @ Ť~aSNMJڠw4 5;yu84ybaör8ԅoqBuWPw2,>J  3s<p/<<>|w J#左u'9 8Nq-##p%5<):w0ecΔ LJ}28\0#gY<Ç0UmF;h:]KW~ƴ_a|ְd?w endstream endobj 1702 0 obj << /Length 1550 /Filter /FlateDecode >> stream xڽXmo6_!t`#RDumE5پxHV/$dі E^ywZ! }[׷vR |y.ck>te_R9j͛$,UdG)*~4Tm۝6 Qΰ3]2%}̲1C>:d Adjsd}bdCļ^l=z0z[i1#|z^JKM` x油9hKբl,OSCē|xM(}J A?ОJ)C9YcDA[[xeXktc x̠C ȘgcשbuFy-Ƿ.ahzՕh\Udzpn&r. t/4h>4+3"l`IL"Dq띰ETZ9ݙI{(K͈UfDX<( m7Ĉh"A!X:`>?^@ P9fWkى}Q J|Ew@L:AZl&ʅ8U;JUWJԏ@ԗd㵺ύK Ndpς0/v.qO0{ SkKoxvH T~erwuAw˗ΕV?y޼wR5Xרz)x,y+/w7Y_A"9n; f@,Ɉ"=sEI=_b-qx V6B0 kEdűb4 Z-, PERj^Pը1Rb˕N4NVtp+Hdxj,;e]hB@RD3QEeri$ԗ v˜F2;Qʞ8`IͿBkjNK:YGd$L6;Gt$(̔ȧ6dž ݈82YL M%DsT߻\f6+ )"?4VOcHQCIMVCf *].DC)N@#O.UO <=F#X1vyڟ=خ {K*Ѫk&П ~kʍL^Y CMW"0voo"#.B> stream xnF@"ʥFiH 4M%-6\T~}l)Q#̙ћyk{?~<=;$wv F;_;m9~ZY/<; 9&(e} 2>;|p'`1S3s"Q#<UZ,̪2MvfmpȢH+YoZs]vL(2?ۻH%ՀԄu%BV엫IlӜ_.orح}a< `_':<0FV SbWY7$-֫ڔɵ2<n%xUEƉyqki`J1'. %1q bȬD&0iϋ Arw‘FBұsa#n.V/>3c]0œ)6$~5`|8=N).e(EYs* 9+L;bȯJf)A"NkOOhưA:$`R#P\byb$4#  l;(Cqgyyr`=9ky cPh͢?{}6{Fˤ"!@oY/o1KbFBYxg-<,2`rXa:"mT焐ar0F!LkF11`2vkM~Ke J&8, zSٓ axnbmqmω).;ʍ/D3.2u:M@$GHLSR#Q+9@e5gœZ-|\w_uL5`d1c%VY(QP) E@sTTXN& Q;R6bz]*GC70ԥd"īQT.J]‰)}aaVx](e]ljw{=7fgS(ǡF@`Xs $656Z$ ],݁giY P<gr|Aqh6?7"mۻb$Gnb_&:76f7_W endstream endobj 1747 0 obj << /Length 929 /Filter /FlateDecode >> stream xWMs6W`&3!O͝4f4Vrqs%Xf"Uv%JDɖ&iF o-Et9m:y.HcM%s",9C9DNm㌧`741cLedJş;:!ɿ CKrr9|WuX ]OZ}:@Bl"ER(-lW3c@58ɰhҴq${L?L\EƶBxMIdE|5s;MIͰ* v7x< &2Wڧa_ Rjgg~=2K~4˺kszDyMV둺]S/Ñ~8CÏt㶔V{e5o-hGTniϐ@Tm\ei`3̕@ Q VgHn j2A=Jŧ kޏ__8+؁ZIQ֚Ɵwˤ e(m}\@7@gFX8QXΫ]Ti& کĤ'!@/ѓ1V r}wk-ߵT@"oj(\f?F2P2=A}| endstream endobj 1656 0 obj << /Type /ObjStm /N 100 /First 984 /Length 2331 /Filter /FlateDecode >> stream xZmo_- 0H_{m]ۛD,K ]Wwi;>gYYe'Aʄo.`M,)rꝢ(#Qf\7t[QE\TJV!1`FSg1] R,w"C#Ȇb/)?"f" ֈ$('+ e#!n2>va$$) 9u, p'f#Ab9gל8qI . .LQ&bCQ eX2, (xLVqK穬_J3#;{ '_m8<lY` r) B(i@Çx)(%I, JH+0XaM2~$\ˀ0*R(EY,Du*kk^2hJeF(A"IAP0"1,Dd *~^e`6="Q\-@^< +la('SYH)LQFuB1r73*b3%eH 4` L)vH>Vb\;\tloFljeH)h茽5L=ф庣r1_C5y%bOArUæHlwRI_jrqqҮթtRM^-n4ڃ j땤b`rܮ7ˋvIInI\kI3:7Yˆ$|$zU}'N TWBBP-Ǎ_L:ܜWwe,3o&eԖ xLY2qX[6Zҩ[=/z&Z^(Dժ(K2 gf.k$ƐgQ;qL'*v=rF `jVŬYƃ.nGU c;Qd(pZ6PEBQĽHƇBo.Fr93to"v[9m}Lghh1hnWpNV%@Nwyf#!i;D(za xUڸeB,D#Ez8f٬Gh #aB3 kn`PEӍ}ga >^jǠ Ԗ$9TcKR dM ->ʒ~9 5omw5wz;_ۢGC_ڢ~cccccڽ\\\\-j9W˹ZyܦQAQ7lnDHAO, E\vek8ڷl=rp4ry4y)`9Qѝvtʽp68!)bG0CH/VQH#~rѡ̢ ] 9|svv3tf؜}\L/ϟu?>Fϳf)ҿή5l1kǫel|5ٲ5e;̷Z+P~۫W#&Bu\]! 9hޠʆk =ȁR?)}a1Gn3A@Ϭ0*샱oYT8<~ZX?7_V ov_'eQnvB(n0|K&:!9cej{h4Ps ݫE#FѶ@ U6G=ǟܡjݯmm`0'y TWBBBBeZje c8y*>D lhA@N˶YGӫ؈;p dAU8fp;9 zP' وP6"b!|e`$!#WN"H7>:EQzl0ʦ"lKgBR]/>dT?^(+I9@\ݑG~'<5Zym:1鰂FcE:N -\hwʅKͅX + 7ޢra}Š><{΅Nͅ}pȅk>򖡰Fq6Hq/pD0Wzx}s=bt^^ QKЪAg> stream xVM0WXˁV"^; lR*Mݠ Ig6iNv<ϛ7&hN/B$ ` Z,ղ̧oO/ N(#pgLyMF[c9co8/3UZO/8GI|Q gWO2~]|_ jU39@u4hA>L8o z esy k >DskAq#ؿVM`7[)B R](Pj5Nzlm4P~EUTVQ nHD $@I> Z34GBCp] ]>TNB*Hːujk°w2mY.U3|AoTݎat:x :g4\ILIMZEaGDpvEIgss/h?&wU\WIH1goGo+f\5MQz0r,BߐV,?:p$Ľ<*$S +f~ sXE\546/rR&jBxAh٤ܝ~ .W+Cz4,t Fkmp4[˔im+>Ĺro)o7rNQ U Y=PsmHcMv/>6 7ͭhN+ [I@Uve[k =ԚV,[Y6!<Ey.|]$I!(g> stream xW[oF~Wd0;KWMUWj&n_}paBPMm%0`aV% h+EưjvnP ~B** ڸ]_EW(uO-:KO;r 841; f 8|1q^$3pYh״p|}qI$a1ܿmcvӢH=ȑc/ĻysZuhC(x5?Jn\m#,= ,Hz"Iט:wEGzPZLY9Rhsm6B+R ׮sZp P- ڝ45Mt|妋'BL(i~sπ;N=9 +(c&WK# ܥD Rʇ\VmWe>f=w_{ endstream endobj 1797 0 obj << /Length 1385 /Filter /FlateDecode >> stream xXYo6~_! HQW>> F8A K\Ziw(rjfpspl[wm>m5x;VBxjmaF,߳kX73VǛW_>yZIC2Ѷpo糛ﶕ/| U-(u@άҡFŖjp[ }m!Aa8fUXמ,˚,*ůD2:l7| G ~(<:aU\:-v.88@^ V_LقviokYT7%/{ܕ@lA8>BE͹XXË}*V XJoҭzŚ2Rڷ7jɁyDz]Ew>czuQÙ@׶ |YXyNh\9 lD-\"E3@\BEsC$/YSN%vCDmB} }TVR_nrd"@M53-:`DbL~><ǦA5X'f,jS*+jM3aqTci\'ݾ^P!R (wMζuu0gj_+PIÀt};*m !(}^10 Y"亐Vvz[<ƦuVJey4TPnyBTUOO\,J !NpnhרZ~z"&?(.Gè1v gC`dR/Fܵ~OT3Z'ױضLvqkFuHp~6E"l]' $!|0su84Tza2o|nI\lb[A/&ViI 5G~o% (l'Q`v:ClNyܻ/#w!rJ ᇆ~ 59yN c(6CDBwL- t^E5Uz3:/\wZLOȀQ/xp[fkDmQCB)? f}qLچ_pLOŝRW0):nq7cB^iomoȷġC@'Dî~~rr8.8(ZoݵeZ!>rݵo.B&OG{r6NA#,xz?9hTp>}]ƪ3q<ڡ,һ!ᗥx&Fm*:$oRnWR8 fq&[&%!pO36f QQGD9f rxʢU&Ca8Vz5TQjO:@g _=t endstream endobj 1816 0 obj << /Length 1439 /Filter /FlateDecode >> stream xڵW[o6~EZl(VgyX8Zt$yiwx,:-G$E\f?^^KPлƈqF̻sx<dF!݂.i!Va+!N@rvu ^U{zk(`0.Fc$ 'V˼dnL;WA@9)Jb2[|W§r]C/7)L6+;l1i0Q=ktkaDsdt~%۴7]^Wb9ݭ4JrcA C!'IrۈsahfD;|:=kQx)hD{+rP r P ~slu-rcV~/֓Ӷ'vɲ܅Wy^f6F;m (m)=?4b;[^G㐜I}Ba'q3Pin |bDX9µye7$в].:V(> ψnuh"c{.sP<}2eW\!-oѫWr9E' 0@ٳG! u^F@c?VvFo[#AG7((t8Wm'E6ir #?rS6``xtݬc[3te!W>爃lt9<.5-,270.Qˊf.Nb4 Nk{!TT4YwwV 1M =O'}fBtER.[Giɓi[):;^| endstream endobj 1833 0 obj << /Length 712 /Filter /FlateDecode >> stream x]O0+,1i;Jf@ n^mt-~n@J\m§9~s87: [ 2e5!l@h2(l d14E8 `#9I Wn5YT<Ѭ:[\~RdY>Ҡ0mRpŇi[lLD>?G[\ͬP_^q8i1QJt^,7{tf7ܻgS{})k^Gfե-ޮHԌ|P&2-yZPEA ,d>H #J<;kôd؄}?}i~K`?*e忔j;R 9 endstream endobj 1759 0 obj << /Type /ObjStm /N 100 /First 967 /Length 1739 /Filter /FlateDecode >> stream xYMo7W^ 0$N6MȒ!@j+&#=H#v8y) g(7$Q 1\RxH*"p}#E D jI 6ɥ oH ىR0JS|R#xr\ΰµu|%R`COE ulEW1/!}$rІB.y\j_xMD_)EÉk+Pex0':0RxIJIXD\9 u dDI ЖE~Cc}E-+qMXb؏*52~o2;(XE✑gbe >$ FpJ,#QxI8&ˆ006pYBQ1FWtvXvhndhԱо)/1CBc,:.<LƏA+Y?sRPz]S-ި;7tuoè{67[ݝv?u/7TFQ4oDd~1j%$=twGOxa/Grp|ydΈ(Y#r-:u";.#lRnqʶ&0=t#23Gߐ.f6+dr:&Vh8` F#:+طh AIMŢ퓳۳~%ǀk]v߭>lrl~5Uz ȯT!juK X`|vvcӝts׾G>8BK #ݜ_u}w؟_>=d>}=c( wDz~ {؀цU;A nШІ,7}VEG˦\Z̖P`oFofF?:3 l-0JO6Hk#WtK%4h$(bu_ J*?XBWcê4Xt2,$% ]rBKDށiU1[N@b J|s=}Ϸ'ga%Y|zQ.sm(,zsN+pZ8) "]n] У-Z)X˫whv|75!N1z vن:4; eh]TTMɮGUk.H;Jv4VNHd-jCZp^w8*Z> T)މUyLOzU^e}2'ڠkoU<9 &D#s_WCz(N4\L?0by/MVs/9//Ɠm!d%"?ls8gד~+zl0gA)R0.taz+C7l4J|d6WEa&~G{{/6i撶)RP~` m~4469jDk*XR҈ZbhD{(;Bn/\larLc2{L{26 .lNXv1_5c$)O no}n h M endstream endobj 1860 0 obj << /Length 1732 /Filter /FlateDecode >> stream xY[o6~ϯ0sIdmSl:uAi[,~](Sae#gl5ŽF>sGh~qsOR!'uk -/7ٲTWus-)_l[^zpgW9JTfrP4*w9bmBguEa=N(%'۸(t=$DN]>$@> FSQy<(!9JvR'`0% Qg eg nˍC]n3@sJy#L,6_)LLF1rnsz'abw!."BB[;|F!t FPXئ`UM ȇ1ۥ(?h ~Z-2Jȯ7n_x3ebw%|KxEY2S{)JX$r r3a X{5ʐGn5 Kz5^H5>UϑIFNQ%0x5kR=WgkT)9ʋK`J`,\ X=rx(DŽjK 늗 :xjC*@bpɼ(Y ӎ\dY!Qbb֕{OI: +aO6, Kxİ$ѻb״%6R$8V˨!+GI(y+*M-I\~/6s `zp\ϻ5{dK'D6«%xE|454!'t7X;!v1C~Pܖ)r /#Q]5a7CCdI]8%V"cE(V;Z=/=!w?\\,۪c9C."БuQ kEjQ{ԀzfDJ 5{l>qޝهV?At]2oƾ_׎ #C^؀Vf; B6(>XG45k'S"!v z"y8wiJ8/gjB2nx$ g<+E.{9ٵ-7@\W/F&]#9|ܖq/[k03%̎m&PFdžs1UuQi*Go";լۋ>ev1ڙ.g,I2Ye+ϕ,CJU(bpUŖz46_jq=(M&t=i`EҤsZy_I0,Q@Z6J-6BA!϶'\ q{}Nj:> stream xڽYIw6WЃ`yi5Q|qr%fJIYտAdA9a On'xE& JBN 1N#d\O/.gOfps<̨y̚gPE1hoLaҁl`kYBAF:O8 ~c(QgYz1rKt-Vg @G&V2m6Y 2BP`"t`"jP<̵Rˬ\.6Ԓ/fײ(J}HFyVj B߿hΕѓ! _FDE_YܽIb&7esWWZ,;ML]YVˬHȃu#ws' #b.l2eqgu܁#Gi> R*\@9BQX;Cu\Ň!.UHժ6krR_~Q 68s?xl,D&.6MP|8O-"+ wu)+Fav#_0ZE g2c[ۥɐ\ܭHݮ᠚;~=8JNL SH뾳}!N0UƬWAOlsԽ"u+:tjeBq}+ Y<3jj#X|\p :p!qKTmZ;%,+6)Z8}n6GbElY]o룈MqODuU|j ,a5PE!YۢT bv]v]T(e/+8܊b:p5{-ڢdF .9PH1[u@Q3)'|Bٜ\_%Pz EU[d "'\7 Ķ,{Q[^_+6BkFCl?jw/㌪fÕ^c7Jx,P8>hY;;Y<. O*L>C |գ`hxH muh!6װYUffW>cbē7wnٝNchֽ6kv*=j^9E1;)ѡ۶͹>7s endstream endobj 1883 0 obj << /Length 1127 /Filter /FlateDecode >> stream xڭW[o6~҇@&ʰ [E-^>06h,Ok"Ye5!y.wH pvzM̂1C@0FAc10˯$}KPcXJ+e]/Y#£`S.>&0hMˀ@.~yQI`q I(JE?F8K$8?T[j2X(&%ѹ*Љ*> stream xڵVM6Wȡ21ԢY4uCעmJ6;)Y5)rf޼E,~Z-^8JpB `.3JѧՒ \ef{mMz(A)- Z`D2IкX|LP / xZ A`vb E!9™2D' '1Ae$ lkpQ0v7 W% .Rl%%pϦ^Wf~jQ"5%{F+EޚLy:O挢$fm_.CIH15!8>/ܖ[2uuk Zv̷2m+ qkJG,q?'"剔ϊԝ{yeJWՒ`foG{2=t\j/޵iF8&;/ dܛw|S;S95L}qZg'^@"g{3<"CtkijRIٗ[׺{w <('NI ֚҅pLPkPɦ6y{Km[jlY@):z<4LX\>+8V;kSuĵ}fwO ,ಝN}3%V {[<G2gP&ی:7u#<Wj{MU>p-Uf};mc Pl eLfzXfrkئiyrTeyfms|i!qm8@mnZ}R@rW.pzOg6gR5{C̉X!s5ctjt"3c."IO*˯9tRơf$}2K#練|t5*6Ć8 /& endstream endobj 1913 0 obj << /Length 857 /Filter /FlateDecode >> stream xW]oJ}ϯXf]KPt.IaI6/vlz^;&v)P] ٙ3gAKDtl8qB`.Ҋ`HgcoɵČLmjzXWvҠM0hfVlЗ4CRq&x{!+A&ǔñ`uz71I!4yb?/ZFΖ75rg*XS#(woWdS&U.0#W]ʢy3[wy 8?lPDQبӢw g Y&\1mk^ymWpEABr{UCؓQt8LS8*2Ir8nrڂiup]UME:ŒֹIzUr[y)Spϛ ̓Y0#&\b* XYWƨ58!hA/ tp\! a}4HD+fRX/c|z19k1ppv&@~{yqz|䟷6q dZG|[L1guOp Roӎ/mblgDE ͦ:WZeh9i"GmH;m݇RpÛnfTV 1 AtGe]Qգ26iRl&Ћ˳NM*w\VM b1J l.~-[:lr^6;ih=ֹ]IpmG0To endstream endobj 1936 0 obj << /Length 567 /Filter /FlateDecode >> stream xM0({6=R臢v/m^0)-_2d582lhC`f3xvG,mښiBFlej~}|}Ȣq]s @ä6cPVhIMC˒t |lu D7 b,MK =bWhwYScZ5Ņ|֒kQ H@G&FK4qAu~lٞJt8cqt@rin(m{sC~Q@4wͿﮙAjRN&q=8Æ9=44_BU8.cYHΊ,eYW<2 \{ 0-t"DsZM<{=ǃ =0>B1)nFOHoG=x*jRqZ$qtEzBB?v]{Ewb endstream endobj 1940 0 obj << /Length 1417 /Filter /FlateDecode >> stream xڥXKo6WCm f$h)ٶHsؤ! Fcz5,ʊ#wd|̓tf3gۓЛ%$ i8]\!΢!Gg~ċ/L/  oRN-{ D% .h&; ҃_kVxJE2XZGd,C PѢ0Atۼ¿k|zVa3d(> stream xXMo7W^(r#@i)hkjVI.7e[Ub l> gjbՔ\N₫ _uT],q4p&b]ԣurmBrل쪴ΰA4 9`KTpɥpb9kRդajUڽ"Q92PUYRvbЋY@Z-[- c b6Ed+& /9f̈$2n%j+3$ Vˡ,٪yf  JePZ8 3`O5Z.Iq)Y R&`%W%=-;T"/ ?q'  Tn*`I- 9IV` .3JPrxhN9ôQTM{ ڤ4mh UXf4ԣZ#ADVKF2dȐR[!,ՊIBC:i@1DQpl5iQ@5D6MYPAYHXa Av A>v_QPX_}Qrmo=z5:FWG^,;B7̨f忸@O}CM,Tg (< ~qox0x?pxJ<>C1$_({c %Wlɛn}w{nq[6YbXy&h8۝'"6n< '|ݖ g3d:IԖ>(]gm5##V$9WԖl eWȼ)[h,)+KʒRB)wf6D=f$n]#NSҙD`C:DU]$OV9/? f;' 0$f̹p r?wBΓc? 7(r[WKآ/DI;ZQ| y/hzw>ٌơkNgwnF?y2|\ދeG{ ]vs;]wM[p3hi/hz 8o!{݈Q)]F)^fT e+U".g+Gw5qE#^\ї[Ǻ|=j0^|=k94Dv{% yBF¤FW=%m`_N?u[tQL^ЂS9QNW,ဨ#: sGt)syq'꽠)$Wh5vN5w;QSv:N0L)NÄ}\;<߾Fwf ϘmK ھGfoo&$]A17yBU~tpӶ?}vs \_W½hzkRl> endstream endobj 1948 0 obj << /Length 645 /Filter /FlateDecode >> stream xW[o0~ϯڇԸc;=lZVI[S/14S., s@Pix;; 0X'u}N8LF:#&|dVÇՈ)6c~mbzb/BqR=[bJ%' 6W<1b"t3v=bq#ˡMkIdRE"*R5SŐ*/ճ&, 7/g4>&/?'=Ch|eX*γN^))=Ƚ fc]O8iRdo;b)a z##Oh"]1T'5BT=@ćñ1ڱL::GrP -]' !eF|o/wq|э>N>vꏚ6'Z}n VoUz{ Eٛk1}:\2,~CTTo=N`oOeUD_7gPx/EDi7B}MM4 endstream endobj 1971 0 obj << /Length 1485 /Filter /FlateDecode >> stream xXKo8Wae bD=(m6)X{i = =C=-r{Yi>3Z<-ŧ?/Ilx\/ee Yscj0k;? |Qc>"J9֯\7tXf4Ry4=2, Kx$R 6yu^`%JxYjPA|pIf ^MCkvL M¤Ñ؋fy '@Sc\rS,e<rJa!!3n6) EMfXFc[^mDMJ40OsemɼOEw^F>k].s 9#orR`C{ymY5x֭xȚulq|3/bQ|>b`v`7GC@ Ke?, .VDuDm>O*pM!n I4s; =nbyJ5k,K9:I.TO^+  x,cOqFD~I=CƐb>wWu!I/mU{qD, z60-S(g{]TEǟW=V?Pg-j-|s$<T%nh.w"~,;ꦜv\>њZy 8sh8Ž:=uVj3<РW X ^Y;'ӹKvYԝ5I+Hh3&ꊷ;b-ou^'ąKMώEp0gRHh$,6Im_ـCڼ:d sٸzhRE` PC/+^TmZ 2C]fUCI7?ܪ$\{3?Ɖ^ g ;/;Ee.s*B+}ߛkBZxݒaUW,AN6rd=!m OI ۫1q6ѸF > stream xW[s7~WL3AV]>خqic>(ZGp}b;h$H4}ƈ4RGIп)'ήӮ4eThvϮ8ȦL)Zxg2r ^~.ǟTffaL ʾy3&}X?Ղ#+8DyP5нJY?XMʨ󵽳>bsQq:G VK CZO$@(=XK09J==E\n)dNt,xQ}w\)@yYb\4^*u)V/_b<ԿeWP/ةH^Crʝ8ط-gl(yw6{Mhc-bw87\]4|?,Ur*:zW޿=zqD1nƣq{x~!*xՈ#zhf}fU6{Ӕ4Խ#I[5 2ܽe> ?= JRa9"V}ۻ&1W_eU,^\m| lD#BP-Q,\ FH!4|obwqLDoNr%RbnA-i Z6Epo 'P 8ԛw֘.F'0iL,Ă=UJ @Ib*S jѠH<qWrb߿U-=4^va1EHUcgx9vönpO7ݎx{[KΝLz\&5hf|Y opA0Bp4 ܽ3+{2s#,P ~D7kq^*Q Z| Wr9pvW~C+mc? endstream endobj 1989 0 obj << /Length 712 /Filter /FlateDecode >> stream xWMO0WXDj⏪J-^(1v741Пl²KR3d`S℃%A80YIt>9?}K* T[?*˧ Ժ4 ~x0Hepv@f7OR6K0Q^Kol3և $Duo"Si$AgEŬ(s3_z Q\%]pΠb!i_XyJc %;ĉ#8@. Rp[( 5T\S6B PV{ޤkp.)uϥ6"sZz1]Uq&G֯N󇮨2)ƉTl G%ɮ-"^ PblOXȖ?~ > stream xڵVK6Wȡ1$ERbm6HusqBksm;0 <>|C_WaVIx@pBIZlr+]z][-޿}PF` 2# 貞}wvgOy~у= (fA|LyWErפYi+u\j>/S$k]־,f(%xHu6[}53)St7xcy?J@`F1 6z\ljY!(oup-|(5@`&=:7DD1҆.EX%nUds9xLT5v#TlQ#~z;CZ%{d#ԝN] A9YaøM.\`} ]5Lf fgo[aQ z!v N㲴aA cU S8sv|7>b A/mOv哔e[0o?dPNYԿq %`n&@PXF;Ahw-U*L.vzsևa]84r2>.ŭX4aLĩl8q"!aO> stream xڵVێ6}WC$`%%^niflVmu%˕ԅbtbQpgfbg`z|r~'B3_:cP |gpn]N+1 F!Oc=poGe>&|τ;Sĉp|r{|(tiPB3fgـt`)qHǻΊ8NGQHzDg؍7Y-ZW,=*jmC S##UkNy!LuZl,l=F3%!=B>n$βG3 aݯ%&vKat]`Chs6QYa}FeUq}mw]#H]_8 `UIr߭c| Ks@NX"Ϳ.;HBl4 *Ac򺌷뱼QaR2q C睵嘇B+%,oQJʯ~TA ^f479ȶzoɣf{> ĈGgvX 1]> stream xVr0+<]3*ɒlte` m ҅IƃL_^vvL垣sоz3N=@0 A\lA@]lOC9L"*Jv5!"O2*M,hna;6c3 xkB6Zz}%ϝ1p5͌PBPI%t5Qx*/DŽ/@Ӡ+5jY?P|C۹˖^I 2-RH.F 6LV1/z= 2FjIDz4)"%Hjt 1 AVc*WWniM{ :)؞%-Oqp(&H'q>Q~dB)#Ȧ.dӈ絰>2 Gt*)Ib?| &OJ,VetǸRfz-2z ׮.CS~Ev]N.|fxeXVAdrcy2:u7-(SEx5ESF>"ݣ&瓋flb1GwDDk}9m/s<&ʠnFNA5F IF߯y T=_YbPʫt:@~T96͹2:"jx:[f~vH7>;JFpDݗjGMZ=d^~q XiJqӻr5EWfDYO ,Ǝ@a b˄sc\&&*x 5VjgB ȗ+fѽn$rVج–g⟵N_|(H;#mxʶN7M5R endstream endobj 1945 0 obj << /Type /ObjStm /N 100 /First 963 /Length 1489 /Filter /FlateDecode >> stream xY]o[7 }+HA~,ۀ>l &^,-C9F:/1uIQG$ukJ.XY]*Mbf'%;jcȱfK)@..3 $+i`qXaMNKp \\Xi. dm(I7mXOUE $x m] WBXT Lq48f'%HjV&[&Hb۔b*J xTbBVaA j[T  ,`86@m8FLRHX5!ͷGgxl0{L$>KsJ\K$OSZB(.Ņq-X, /,*- #w@dHMmLl!fMm+Un307@ed3(l&LI"HuM6S ԴQq9/ f%P\^#N@YMCq(ltfM6aVmOlmNƚ84a [#u%EgXqdx>aѣG }8qrm!T`l1@Z uZo`\Nm}o;vojinM|1hx Ωp4}<\-n{brz6~2䚽PSZ_J ׆Z KX߄K(tQF Zԣ4u}ƹސiRY4,1dtﴃd%z34#ƒ[RW+q-G@ ]܌_щľ`{TGw+z>t4vjzh"KMY|5|҇I꺎*t/_C7'*{{5w=`qeR/b]m(=4ﱉ!qv>g&ͭvPnvqd\{b|&9{Ah{58}F-wnHu!%p=rt|?K8ǵ[ |խ?_}yp}0VZeKX7Srvq>89ڹG}"qI-rK7Ajz+2F,eʝգ+^Em@siMMXNvTW7 y^tD]g=pb9R\NvQAhM_U 9e/袲ybWhѡc':UqͽfbԉftRoFnOC[a5 ҍpKXG".tȲz~9?ӦnQK>$NjX z1 +.xc- endstream endobj 2053 0 obj << /Length 1195 /Filter /FlateDecode >> stream xWr6+8If*̈́|t ;I8Y$CvH2ȓH{/r͹9|;C0FLj{ԙ/>/ޜÑc.D|wUbFTd.:f-vv-ʐ'&7B90Sj򾏷{m 16$D0q Gchj E!rR3OE7y$Dۭ~TTrB_(ܺ RʪIk3X꫰,Eij#u#K}`Ң,l VfLb i#w[aA7κƽQKDq0t&nW1 #èr޶݌iyq } B&MB#cҤ@hq !{wmYRw޽Aq4qٴ׹qCD%`# 1o?ѬtH12>R!ץ,J~(tʕ~xj { ᰛV#z|{`/G伓lԌbz> kujZWVn()CS,)U6YJ,}֌Z>c+r.tŭ4PG($l 2VuiRHܓ_X ݸ~r+qB0-SwuFI% ՙN #DZl%QIY2Q~?~V\%PU/TzyAE5*tCBe }{}yimt0d endstream endobj 2069 0 obj << /Length 947 /Filter /FlateDecode >> stream xWߏ8~_JRqp=iwV}%,=R Jm{ `{}f?Wy1%##ƥ$FQo><^믦(+ٷ zTv 7Z[6C3o*ͷrPDIP*Fs3]22]S`:oQp+ d)aX. BF$2cA!ؿ g? @A5>B\u tt[z-Wjdb AgTּ H Db$%S8#:qeu8JD tDYN$!X s_PD7]ZXsT:ۛҎZhSQ$8FT? *"(-}+1Xz:]~8Ҙ#H_o}j,q&nKLiuZξL`t5U(D0/>| &LACȼjXa OE*=ΕRMX체jڮW2~]1s;?3 D2;$3!E~iʤHwu%, dt8;6g=3l2]d{; 'A(0Bmj2g[`{ }I2]6t_PT'?P_=e G4]FF\q"ΚwMMQp0BW+mȇR.lnz'S`oQոhwnic8hX{ȨYoMSL W谲~";lYK`DVkh5؆mz 9DM'(?v7݁imGҙ EpH&;;7V`GW }j endstream endobj 2082 0 obj << /Length 883 /Filter /FlateDecode >> stream xW]o0}ﯰ&5cIB^[)Ii8-M~!@R}suB "zy~qXcD \DHEKpQ~_͕\K,?TOnqT!;?:L/aP2|Fft˕3$(JphvKJp$(RD`"]PK uLWPl$C."spͣi63$ZGaNBkZjIc|6ObIT1Qwl8XsN0;ۚvZ6Iw6)=IH1{y=Ʊ/{~|0ӥmv܏3[ܦ#o|o$S$%kIu8ɏ0-"TsX݌0yM]LMbgv^ R_$6?u\LfhǒX~0?{+35("]4;;c생Bc+!tFo㐫u|olw}u=0o'dvշASU*ŭͼ%֚;|ߛ {<A:v#d8Jܘifd#r6Ov1j6 ;vl1&vA\;v4rZ/TUDܟ ̷] OҦ?uLGUMZW/1*p2?n y *lJ|(lM&_ a+AkqwjDus9q&eۛLywejrڝPz)ZaUK]>ρRG($x`p>(GѿЂ}浟W'1l endstream endobj 2107 0 obj << /Length 719 /Filter /FlateDecode >> stream xWMo@+,r-՛Q/"RFĚC p`f͛yway9̓HF41yq`K[@"Ep5z܋G8&(N ^ҥ-҆ohC̑:SΩMd!IPBS-~a'7հc!HB!Ijo;y=zShOi6W-GG>3\o'3c TkSeS+HdY)G2NN-q(xx[p`$د4K*W-cy9LN^ї(IWz/9ֿ<Qr<j4bPAw_@1;J$"71V{'lg ٲ%)!@i~Uc撽*SRm`beN=X?mܮ%&4) j0st7pu{%||(-JJ"!pJOO3w> stream xڵWKs6WpC &$=ؓLm%ٓ(JbˇBRw EPl]br: : |`ENȣę$pAWzB%8Пp'G91ϤތRg$ƴse\P*^#=7 HxB߸[,#v,Zea.]ooA7FFsˁƁzU9"_gzHz\uVf( xwIrи`An*]VOV0pb9Q6Zܺ 6Dwh0Q(|Q S(ϰ1A/ 7s1e$ᶉN>-IWzey/S1$l9Qk 4@;.2I!L!1au6uJI7z+%"$דP.%kuy)jz^q8Y($Qj(e֕d@#M?W&㛱c̫"D)ԤaanAZ "q4{@Svf F`"^*b)M%t5.V nUq/H2^'eU ]­&QeENƒ '.Up0~P!g 4\ޖSN6 : p9CqҤ2$1R:D UQ.)zM@Y H=2hУ䋆`IG)Ov}3e߶(*ClXgO#|!ij ݰN^".Z~Pe A#؛ C7#>a 7J'BCJ*w*Nod/fġtZl߄S~t1vCV:a ].Ֆ5Rcx3*dq%lNl䨎G]RmRT<1Ыc2߲W }_0O,&(VZ1 ؼOE+jI1՗4{x<47?lԹiWTC^VV7]A^Й-1QO#,YO%d=5Nhlv;%H[y0T=Jg3`CItmTAH/6W>4pkY(*UiL1t7>OV endstream endobj 2129 0 obj << /Length 967 /Filter /FlateDecode >> stream xW[o0~﯈Z1c 6$!S郗z#(mJs;]f]W.*OqpdXDD2q0(bq bxD<Oԭ.ߩJf/  ՒX K[ܑ3G!x&7Et CHF<2KU> ÅZMq]6Cg|IgJ*bqtCO>( Jm?[ZhQDl,N=k%robcֽ'nr`HQsNPUݠW1|IO$1ۃ@(px$,Vֹy:P^ mac v#B)Dc$Lol0Kl䅀NUVrueO! `ytCC)b$nLIt0ĒuDbf]MR_Z1@eU öjDMJJ[t=` s. |°~_ endstream endobj 2047 0 obj << /Type /ObjStm /N 100 /First 968 /Length 1502 /Filter /FlateDecode >> stream xYn[7+l7 >E[ VS#dHr}Pj|KAt!/A C .&%Wq 3;*q, ܠل$e. 8(;..6 Ub/` {D#/@Zn"J\{3uo\w<0wKSFx1|;t/av4όAw8Mg6Fףw0 u {) JO on5_?mʠ;}ޞ_] hڬ s !11DŽnܚdy~O?ٻtp>Ҷw 8Z^/ @!A[H׺3OwhՌm{Y+fl;Xaߖ~i'T[S/X6xx' k=4ҍ#F_4]JO0`; u{n:sq>S}HHDSac{He ^cD;Dkξ$ Z8M mLXY8ٞ;:'lV ?>VrvGNom mOwno6]So_8:U|p_4U/ѫ]KZ9qSB!?2剧ͮVV[JY撼ݗDV-,?ܺj[]|3.xt"v(Ęn&o_y/Nv*va"mE+q<ݠeeBgQzEzB8ĉ\W4S~z3m3[! VYY)T)xo0̹~>lq!3h|8ӿ^^_?nϥg[*",cn g|zaIB1xQ_7&tl^x>\]ޏ.gۧGJӖ.Ղ̣]3hX˔eb%:)խj_!s endstream endobj 2148 0 obj << /Length 1334 /Filter /FlateDecode >> stream xX[o6~ϯЇ@Ő=<0yhܾ}`-:*K$/5,+2 Py9߹0{ůˋ˛824k`0(2f Y~ytwqL@s˾LlZMvAHPO1Y/sV!>!(")*wk5_q?qBHN–)34@Qo( |_R[x]j*Xh.I&es4{4 f(M19>$v#pW[er!VxY{y`|VxQ\%;_}dŁ;<8I+p0C0sfseYڸ,z̴{~Y8ͫS\aBN-N'50"~GaRluՋb"hAqjasD"C%HYޫNNbW}s.dOba]UNvv\[w1l+]V-w饆aZ0_5j7ZllLDi4{f< T~;mUB-䢃r,qfyn`1E~҅˾BiBf@n\.闺_-W!g-BBzk( l|9_ygֶ.]MI 13Y5+h{A Si1l[O؊]Bsͥ$G{?XBh4^}l|-(IGBVeH6y?zXSrU9 QLA F$Te8ӆdVC#Jq=Muk m ;7U7ik_)Ҝ&jSUޱ՘5\>,w~_@R-fem 7fCE@\Lw9'2Ip@iVaW(*4J'꾪UKtgo.o"DS DȬ!QT{{:,aQ;jyL`N8 P|{;┹^4vSv& ǩ8ؒ^@Y)^&b4Z ?s! &z 7!ARh×x'LToN7'z>m(>#G@@8wOskbcD4@\ĝ)% %FKPGXl{n[Ľl;@[%ϾkP$vӶ  amGõ.PE G{"lentk;т'@c3ü8˿3w1Gl~U endstream endobj 2155 0 obj << /Length 899 /Filter /FlateDecode >> stream xW]o0}ϯڇ%ZqmcMS&jښt/Y4Qp&Hv? '4_s="yԹX:rc2un"$hܽ_~r`6sBebK:4u~w(L kLu|xcbi8\yoͱy>%Y:෥ldرiȭz3H]rVoVIOB[]6)cǸ\fȘ&únK7" ΂Bn-j#:Uf&?.m>Ln\ ˧_.zAHc h~@O=pKADs}1|tȉi)$ ;Dq7vD_y-tNK5̉B,'QQa/$"]ODb’A֛$]dDbY!$n)q?$Fu$Ş{vGIwՖ-{rtb()2PV1u u_Q&2gvdql efΖ%l.9ZJUP0`Rr}hr 9UK< Z>ZcF˩U\;1}<5\ KVD,-Z~zN]=:EW*<UQu4жO3}ئJח okn]4PFq(Û! q*kzYE-R!XA)/f(v fp^KJ "ga8 2^E~!^j*ѧu_ˁ`Bߎ6ٷN;i,`T弎@,eRT[ۺ]/V$ endstream endobj 2169 0 obj << /Length 1484 /Filter /FlateDecode >> stream xXK6Wȡ^f(>>)y4@o/=(2m+%GI=,n$@/&)KÙof>N~^L4PH "*1F@ 8%b\M%^zBID 7xoޛZ$)N0a$5RQpc_, dVp3v}`a B, LRQؘbN8.B<]Iu)^D!v9}!1 /Lt_y33(Qk bZVygUf0K9]ENiv]ât|OOAC~kU&Ds.L}-*Mly`pR;{;r9 s\M = c}KUi K]8#I=2+pa 9= "ڬIUęS⽮:V26}$ Wިm1Pۈǃ.RYXmhcƽ. vFCDHHl8k^Z)^=D d s I*V8T| e e7Ni?:|ncP~2;Ɲ6mBI:xGS1;ԜJdCU&GtdL48@!LT?*oҙSC="{ej̇Ã|!a׵7#+'6 r/~'zgYqXD &B!*Ʊ(R9)?#@JJX90,/IgR~ l:Mst?}d_|Zn,tFXF םDP;&J=ۣ!3#4 ^U`!92X縐f&l~ˢI) 0soyĿiu|VC'"f H5:<%Υ+tׄZ̖>GD4pp{G-X6_7u]/xLJ]b':p"$3dj73:@mUc!N1>ex:F &˧"C y]p(nR߫T Cbq`޽I1< auQM;9wՊԀ+҃$T$n/L:懪i&wÌNz#޹z+E كp*N3.c&A|o9·.> stream xWKo6WCm bDE/n/Pxۋmӱ =\INÇdU;("89̓s> ~ 'w8! |:,PgviQ "qu-f^O¶*0buX <{%]}WeGtP E Ѝm(j G. a?+TTEOq5R)J+4B+̗UU^鎧`hE6BU*3j)#`ڔu9>"ūO7%2B΁^? ӈ&.?9F$ x EKLˡpB,o}#\%by6N~La _E }"\,\I#7/40,bʍN)'THdL=ﱷIiHP>D doid߾LEERLRMt^[Yţ0wF_D\G(8Ѭx"5 z6>I`{W|vdu\JQ'|(2÷{GJ=l[ryj}%>7EK% ܱ'rF}rMNj;kNΨk'!ߏ_Hl77e>%wV`5^C>TZOziPvU~٧X`P`Ωv1GߏƸݙ> stream xWKo6WKR)nC$E^\qTJr;|H ,zhf8o<$ܛ=zc0 QPow+ #s_jSOEJaw\B;G' zjPrLuR XR?N*\"a.4OLB2_lSzEew8S+|M$IYen|+;r?jYqld2*{حq-Ԍu0bࠃ;+s٬ C -F$- TvIBKEribNSpV`0(J.? ދGnRu`@ 6k;gNB}H'yxi3QS>8;NpPv7T(ob(Ĭ9W(2n $1 osLsxNՋJ- q^`1BnX2 v2"͹4~8~jU8h=4DX"1ub?_k)UmN>h.2 |ކsmҶ MGJHYpTbd WGbCQ@;*/a='K֥0@BʾK橏g&F~t;;"&Ic-|yF4`ԛ؛{\;;X1Zx8S@u_hv,;Z= -K,A1q57Zp.&.$wak`NNVG *כ 2IYIMAr7'v.'4I4:.KUo~zX|mEpg=BV_1YqU 붾ͼ'[\ SQ endstream endobj 2236 0 obj << /Length 1200 /Filter /FlateDecode >> stream xڭWo6_!*KJ)mCץCng/YU#_)V\#u8}jgjQ@Fa;̹rK,Inz#er^ LϹbY`| @b<(1܈\\}N?8);Z:P]8zyWC/Fc1{/!|tGqD:_nb!veLb(;5'Bc~2m6 B"ǃ0`KΣ:1kY760kb\t[oD&Cc=)VӥL@˔&3/^{ke"4f(}*_>:#9>pa~HG(E4 (!V74w0fnm?/?~<Ӭxv6fؒ,C( gr`SY&#I"Li]ɍ$#7% 9ئQEٕjA=:ޥeFE@!"P4#?﫡Ќ==2z_E>A# Ghqپ| }Q,aB|ߺM`~~6i.IJ"D8ڴ[UM^%Ggfs<Ю p&77R5kFțjYw|Ml^U$֞D~@h U%8 fvrي0mJQ*+ي$3 uIܝlͦ^tFzWurT6.hwnʤ:Woc_\D2[%LdڬEH*+ZgHTKdAa]ޓ.sjO"CîoܷSTH;@oF̮IcQx< @,OGL2u12ZU"TE 'C孭/b];gfnr8,O# ` Y}T LvVg ~ב,o,tqR)C{+hs tý. ?MfhO\բ!bi^?z>Ð%({@yAL&I+O8C1` Li%{E$8Qq/ˣ5ˠY?G:L븄=Z7C~ ՟pgZV? a endstream endobj 2144 0 obj << /Type /ObjStm /N 100 /First 968 /Length 1825 /Filter /FlateDecode >> stream xZKoG W̱f<#@p[ i ;n{%CHʱcm\d!囻q&x"Q)x/xY L5*o6PTfv=@xSfF23eH$_ 1USgc=8\"`pa'`R62xgRa@*#/AeHXGhQODMAC$P'Ϯ_s'p< l=( jB .Y ~7|~:_yPndnaE Җ 䫓&v־7_Wv>M'_6]v])s)eT~d^G6F1(`[F܈q."@^q_7 |n2wJl 1{܉-R/wP_0g&bVߓ;$g}R)7V<y]mt|X qgr{ 䓍>^bu~`3:hFw;#sܜPr"##bG}3-vT,Dl~gu׉Iluy9}'w.F`ϵQtA}fn/lap<[bZȈ[]̦W};BRay6"mN$ Ѹy{}eu'NS([Ppk8sy ՟rwZ8'j=`tɍ 5wIӟ6V X>4[#BGPGpGHGĎH;>MWC cw'Qm|$L0 uQj]mo([#`A*ZqH [\0oo 5<-l5F(%]8Pk XA9mg\}4u@7DF R!SI}ؿUǝҲ@`*[`ChP &$=P沝s(-G53vh|3Z!1vv07:D7NwAtl=`93X2xܤ{OMK%sOf<GiGi⇎u9ކn:t8tqMǡLחN.c@a 6!ؔyqbPDt'P`F1 Y}} &@}ߡatPh endstream endobj 2259 0 obj << /Length 1340 /Filter /FlateDecode >> stream xX[o6~% {ȐdXvX%+Ţ HrRԅlI!x$_GLG.CH4ts`]pl1q_ x3`EB/oﵢѽLKM/WWkh&%=,i$"hY ;(F@2}ns1&qh+RD15bbx" "UPǧ1 \P 7qr>HMd}s.U80s:&F=,*QJR>yP3tL ,YyhS}g>}U>E4Sr_U+vOI,cs6׼Jf;FijT[j`cg-e Dt2IEk” I}٭KY N[X='C "{HFGې {8&*FYMTQJZi0xS-t8 ݇ǎB6*&vr =T p.2(P粊twt/y%i#mOE fK:[ttcW(׫U^TVxfYXP kylIz 1 )RI8"-hȗCp6U^uWu2F6|Z/1Vә6cJL4j3׼T V t5/X[~<~h U~{夞oFʉeѢaƞ=L|  HSC #F_ oADؽ?o $`_8Y@ t&.WiR.<=jR#}ahfzP}*nV~N[.2+.)5OU(\Py ¥zV'VttKe+B'W5hb~e )2nm;Kknlz2;;g endstream endobj 2279 0 obj << /Length 1546 /Filter /FlateDecode >> stream xK6_$"BINmK6 l}?!Wb~t3y}B/AI#0=cDIOZVSDr[f^ bX@&ؐ`;3o9rES[Q4b|ۧ<(A^n" {LCS*yo A3P~S sY,/+JGh -a}XD G"M\9ӁܟD%捬~Jl,nEoJYI)^0=lRR%6YX߸/ܰ(9!(Ts\Ԧ:, ^0# htmkY;huy@Yҁ &!\w Y (I,o_mjF F!4$o3c+Z{7\ Ψ-Y]*a˦>/rRz٥_op .HJ&5uy@rYYY`" +>XAЦȳ4k1gFg^fU4"UEbVR4L 0Jw/AtgOc6E}0 b)fQH$JOS<ֱSeᰞ)&}8B諾f듈jo9<|/z{Wq'o&_'L~ڛě'>c/?D0C "pk)w=mZT *^bpMհb1ruG!5iSP0Ir88#mry,fRN*۴<+<;"dXMnkq˗FW]~:8)[Fd^9g4pnA9?gFEu[R^߶z 8i\]㿀QeM--:Xt2CHKhemccB /\m޸nn U.r2bzQh&&3J~Ѥ~1s*QfӣTuY̥k (5wϾ78_mYᚺnQ1n1Ăj̚uhͺpvJ9}ӕb٬L)^3@; !f5zVܖU%MY`v2aU=P(pzݜ҈jgvbn*cWFp1*ӪK0O9`xU{M ]rJVap6e; zxҎZ zjM T3+svF=ڦ6ڪ>I -/jˣy<[7RV$2%Vup^nU<[_DPw*j-򙫦e SF|V>Zyվe,6ڡN2X'|UQN+~ŲrL޴m6UYƅV~yEKAFg*V3|Pg):3 endstream endobj 2303 0 obj << /Length 1899 /Filter /FlateDecode >> stream xڵXmo6_!`*+Qۺ}Зuhui)k-OGʒd|"ƻNKw~v ԧ}]8XvyUi!Is)B_X^/q!77 \ ;   e s^gJ;Z%"YҜ*gs4\*c<ꪼw"RyӒJ}G~)K48؛"%!d #~ת91kaMa}#RL\Ѳ3 iv"bIk&4MbJ%[2нHTUBU]%eɍ+@o Ukk&L^Bh̋؝9 a[T(Bt'׎xY=DkL'+ !E0@IZ3mGO|} 魸ER랲2ng(@.d+# IN྘yUc@zư.7XZoVC}G590 ׺I}W$P-s]dD/|"Mؽ@y"xȱyA&71- 2"ֵWwY ]zLTO#7S??mY4؍.|xxnjnpeg RS|O]3PXA#OIVaDca*Ơ#EԗxtmW qپ% yXZe)E{¡ A@cUSd wW J0 }6;Q610CH# [}1.Ahb´ ^^2.j. }g1ޭx"Gt=ϺYO )HŽK;|+j5w Qƒ$J>5}  =#>NG8fN'tke޾xqgJ(akvDdͦZiTazLf e^(}w"|h ba5\)7=RW?>)oI:`✉z0!FSA"F`ˬ dwa?T:81UQ%'ok8dw ;VMk-Zl0iQ f}-O/M_]O,ގNbg'OA;R&N:9;%1,RJsys ?[0 Еk-߿!βg~#]Y$lff҃&hNv_?! 3> stream xW]o0}ϯ@i8KC6kup&(3ehOsOO.ZXк콛Fϱ`.vBB@lMCC$mBUʔ4U.n&^No|!Z !Mbu_ CB8w*U`፭o<.D)qvn&"_ZḀĩC̽) `~0訃Uv!P;q^oRZd1D"VsR7G4B`="a@9a< =GGAG)GAnP%蜨N~NF)7X(1N6Ǭr2RH03#x=Dp(JvQkψmxqsOvkb6H>,դ_7Y_[:S%_DѰjvsCkr<߹^e&BYfpVq@b4dx-k5ci!hTxڪQ4l)ȿw^2> stream xZmo_=2r\^@v^#$}娶 k;>9ϐ !q&OU(&HRA E} dG*S>FJ68=ZzR߂Uj2Y^%)Hh^%RcUz0J>HRaEK>`(ՃrXIdbML.CϡAA60옽6ŰVcX+I1 pMbd'j hԳbIvЂ`rucJ!fL$_`8U&QȄ ɤ\%I(F̮¾zQ&CCrv AJA2LN]\B@1Im#*`29:L_zߙ|L_ݜW_&nyݛ>;dz])b "s4xMpl+3LߝWF3VWd?]qIi 2X""o OyiEF~s_=gNo?݈`f%l7*{6pHL2P N?L&$[5|]7͎R8FI_G 75 bO6o`|rx!@c3}}\71rn2} |R!^CkY^t c]^~X|45=q!r7~ \OaUR koBhB6ߌb#J@mSw—e1 @Vtvs="[YLA&B (ÓbW갸b6u(h60tzZbN-K)| Q,TY'5:i4#N2$hD" (66yRe$;Z3&E>BAiE ~,1WV!KZ n.E;3j3"JXށJjp%-%lv.@Sࡠ'1"Cz=N׈oCVݏ`"CoJF)hȓՓ%|}<(R;<)cǏvw/᳈&mYw\~ q3B>Llz;3L[kB3P ;rm*-R7ňzS= 0S =rN_KΤ/iKF/iKv(ɖ%ވ '-#s.z\Q U(smrKߩk ZA} X gPjіv0X-r@뽏GsI %1 .SAAb@9zf|̑;;<Ko?|^-Ub {_هûeo3ݻew=}MB3>d9[ (,# '#gzG Xo7Xcٜ Jvv%ymrc 6H> stream xWM6Wȡ61բ H뜶9(6U#[[KN#LYNCI[7f8Hj|FqD1+D \(+%ghDwSf_ćOr1 رϼ-r禌6/eʄx瓿&1̵F=AK5>G7HPcao D@(JP5}'yZ.Bxq>ÉMx{3$ۇmZ{n{W% +Ή% $H~Kw/MeUVl$kQJyIp='QEUѹ~Vi/7,ƧgeVʿ nG\b*ZS>_l[wDh}jWcwo΂ 79(/:T^k0%RP ǥWꅧ $Z)c3j L479G> stream xڵWs8_Ljf*!k/zsg/Imn0$ 9 q>.v6v>~]ޟGԉQ\;cDYD!Fe\̋d'$ZJjp|a" ;bN["zIIK>cc*(HҢHף?uRgI=]7. "Uve.VM.Sgohi C%/3),4+ڪ[Џ^X4 0\Iap~BQwFVf2G4ߺƈ Ҡ0EH0Gm[\ d)yvicd%TPi3F b%$oցOg`VUjyVJP-e쿸'ekEQꛦL4X~ EQkUAqCT bD }UsQ@T$ӤNi]x[m% ˛]!?At<"z(t_~`]x{j1CAJ|4paڈzsxת$B=t| =#ٷ~E'թo(fNʮr&x0Lઅhx7UF~NP ,i|DC?} B?d#ͧ o޸]^P2Y(ڂF@=FCμ(FRXvZp/Q5r~pmg MnӴ+'7Ip NOx¯@6$n6ZNTl:ìSyX,1G㕁 <0ڃz<5& WLf`R4IOnijӞ/}r ?9"y mW-6Ur.yhm| endstream endobj 2390 0 obj << /Length 1384 /Filter /FlateDecode >> stream xڽX[o6~xeK6w/n1mkœ;EErdq!$K| [ [~Y^#X[.ƈ2=8%"v__+)4kndٮrNdqvp vwj)R±}V`{Oryٿ/E=w(b+|nN-$Nꇹc8k'E ?XBaoL@j?cՠa! ӫUsBp'JE$}mL" !Eiid/ͦ:?`dW4$(uf{Z@_U>όAWUxL z{.h/}[y>j⢔VYW45f.fO#AGl[1|00k)SvI6[#vn >l'( JYl[x(fAF1{rr!|mYEe='indB_(ݵSjb@gI'F(zUdmZ)zy0)CoQerh1)Z$ygxs.]RvBN*px(%he.F&&e$:.ym 6YR}]Ek cMDD{dsn6e׾[&IA nn:ܩз V nG)>®}9G 8vpb@ sǵM݀9Gty'iG %XAcx8.bl;*XߵC}<ζ%a8Mw4b DlDq @|ģ*X~wWؾsI7ިn6 I A^r4qFa"'9fLt1L_: !Z{J6蝅3I0IjK7L4qlmOH=Cϯ;ɰG1aВ<$@{yL6r$3I )z2Ck=B#U1K1t9~+4je|C@{|LUqk!2~ݧֶ< JV郙-js8c8j|8b@Pk C endstream endobj 2406 0 obj << /Length 1219 /Filter /FlateDecode >> stream xXQo6~Ї@̒)IkKŦemHrEJYM=Bxw;c/zb>y~.O"Л<1 X#Po>a{#Lޙv}YLj1r?NSŔD~cԀ aH"lӐ'+i4sX<[8!:Aa"ʪ [禸2[ݥ:z:ea:}|J;; g~@lg'j4I=վ9ގikbӷgv!dMgF$Zgf%3VU|i+L,vQud? ơKbf>ob_6cip.-R K[:Q=@BX@bO B|V_Éwq%EH?":،8F.&I (O?D0r Hvۺoƞ~-}Dح}5C 89}j^QtF^TΧ?m38'(UܺMnjp c^u'lwP'`vxQsh7*Ukԁ~ d)*ӥBృhe i۶^*ށ`PS48 G%Y^PJ;8a*)SGZ/k_Z]tO`4CVG9h@n+.74ujY_>v> stream xZmo_w(eH!];WT6Y2$}[5$ɇ3Ù\Yg2:U& \%rQRy(ΨR9I*"'E6I;!S)ALx"ZYWOXFd i魲dH@<K|Y'=Td^he--$.CYED N"|e+hDi=H6iW1@YMV[ od"]TЉ"1E0* b1ÙҋQ EHESfE:ݕ_bMX@hPAQ:F&Sܗ-$"`DB@#&l"/,#dFzi%G|1JNQrV)QAA~ 33E$+0Dr0e:=[TUrZp T[W_P\E9][W釃| VKy~FB7a(Y-+,'KrQƩj~)xS}z=X׳18xmŖXX| ٤&BK}./g>2ǒ,e!hu5V\xTq 'EA`w +{(=VB~Gxwۻ}b y,DX0N`MK" >%P*s(6Oֻш*JFh!Puv7M 4SX !)ɥ'ӻ7Z@ ͌(BnF2QE,hA5uXuԦh6nt#J鐰GYSD)ƇD)LBeCPPl(T6 gʳ,=sk{eU\YIHZRGc\z.0xA*i`66橨G`ָ|G;qم>bmG^1HŃߕXa3,@(l`?q)rئc_ 9Y!'ةSRgfJq~eȷ(A\wD` ̕]NjI;Z -L:ƆڇBq vI Ev9`K\h9O 4cǴ*f3r]ItAt66B"r׾-gb3`.f/Wb˕r%\-Wb+Jlc%RT{Nr\]>(xizEMtu*;q쉾do0ɡ${x4^~15L hm?;;럜 P{:٧sGl=\|hӵg`.ҿϯ% ߻ǫ٨}6~_~w|Ne޹#brpm/zc%AAqOr;3_,IK]LWط ʷ>v~`6.J"Xdlc{]-eP꡺IP(Wtv|3Ñz40t4w'@0u'!NƿXfʿfW)]ݔ1mR2Δ-̧6[v.uv̈E[:6cz65N(d-zyk섰|N[Nodb)smK!5W86`JvjP#דr^iTogz0cyG9Sޙz(-{}L endstream endobj 2425 0 obj << /Length 802 /Filter /FlateDecode >> stream xڵV[o0~ϯR6`zWNtUCKfC/~C$MS|ᠷwJ-C MKt,c04:jݭrv(Oυ>ƥB..dQ?D}QɊ\֨z@LA=^]wX2[.ŭnږ@d/|\l$rR/.ʅcSOT@GkW+ y"xx endstream endobj 2450 0 obj << /Length 1442 /Filter /FlateDecode >> stream xڥXKo8Wa-Imآ0qYblz"$w((;j@MQ7oF_?gеbN`]Zczc]g|Gfmj~ )#WpDѾ,0ْ r)Sz}F:d< =+-g7_`G]w<'ֳ-Ί#0( fAи8(#wmμˇK;vùʨudj܍=gXYhyZX"캪|)K|eaS!s]箵%}Y3y#k7(jDKuza( 'T՜au~rb{ |(zQi*OSFV|\r4uƤ;AguT}KQ&Kk֮']EbД%,f>G }ް$/.Cȟ ~ܿXdr!gzUprB@鏌Gm[MόTn(CQGjyLL#TTmFdˉh]llϪ-7F7BG fN}q46tc8/-WE:u>'3M/9to+=S{R(m0)Z6Nf̏7?>-1@=soPXTD(^?it@* endstream endobj 2460 0 obj << /Length 866 /Filter /FlateDecode >> stream xڽV]o0}ϯ@@*mlct[[i/l/Y4p[&v``@$TU8s?8x0q3y?\\ '0f9L;ԘܔZ>]\ݓt'fO ݃oڱ6*eٔc2Ӟ'!idO+3%.-An.{lD"D(]e 7Ag,;OGaT7mѪP߱NTygD0$\CBǻDÙc'Rz˶Ry0ı5vy/Cs CIlɐΩQz@9튓 =;w> stream xڽVMs0W3Ad!!wI;%́ vˇpW a!&XBHv>@ 8Oς)3`20)%uz+ݻ Tm!L1~:`5Ev S"!T//zCXoM(y'wc<1b i@N*́u@ƹ(])WBO&7K}G N(:\\0@@X F\Cx/XouYXe!pY8"0<UT{F/V ..WXG#@0+RmSroD#{402Ұlf|zƆ)ז*nvI) ET|)rɩ[/.'Nl_o2h0Ւ\OQ*ҔLh( Ĩ+(E5v2_G1(21 2MPohQBxYEKu2>FcA>*J|N_1IU"JU`.hwu#NjXUBoʻ})J(XVFeCꨧ>!+hD̳jIp endstream endobj 2491 0 obj << /Length 815 /Filter /FlateDecode >> stream xڵVn0)|7CE/XNJkvUS0c;A]ű@cwy(P2x0B p`H s_7%i( T12*Ru{ȹ~^" J0M{/GRMA1Ae>;{_!0,#FEiǧQ2R6Ye3girj jGHVjj1AfsKy3ɪh nB=eb|QIUVgy>/9*%ǙHRSP2AՓNDi-@%s̫<^Yؖ7jh8{Hʤs4}`x:Guʥʭre> stream xWKs0W0ΡLPCfڃ$v29$N/I&#l\+1`&MmNOXiX<]:!TO5cdTs(F2qn l8~vI*66ソB3H'YKatĚT،7.m .rL~r??B p`J7-RDJZry>O9&J~ a#[?HJyn%02[a)2l@!]^5$뻫"C!C"90Wbf+zr|V߀ђDaZn*e: J+digA|Ga.,\̞X:yMҴ@0y me}2i+<^vVeR8thlE}->u͗YVӄSQwkUwYcBb endstream endobj 2421 0 obj << /Type /ObjStm /N 100 /First 966 /Length 1745 /Filter /FlateDecode >> stream xYn7}WyCrx NZ4SY:jdʅ=Cy}%"8'X VGE.%/BV ) zrbŔTiAE딋x JBR)Ye!@gf'"LPP"BK +ŲZ'0"LLj+Q2| & D8$)^1L )̈́YW-\hdDAx%d ILShc0,nCNQC@ $7*8+3[w%`H0=$K(d,ȰL!2\p `ooмSHMF2?D59ɳd#h5#0f:4\[,muh%H泥SAGհ'ߌY= FaӔWP|XGGRû|lfޏ_.Z|-8e'e4m7\nUʻ_df~ ^ I| (Yg9j4Gdyм/aNc*Bk9v0nҨ]Hp3FQnH5??\_3gg^>r'n9N ]Y뿜b:gΎN!X7ע J4öp%ePs5DLPuZX$ݠ_:4yMi~/̾S9uz4?olھK|h_WDxvkH6}~q[WаlXtf u7Wwv|9zPר7m -h`\Eh*ф#D[:Zhtnš2[(Lx \/^^H\H ;&ٍ9.&3A H/9h"&e.۾8z7m.N0cz>p<>tucu/50**WHIUKt2,l5A ĤG?Fxmq&ďc\pANpq獖7Ȍ';` M[6)hӣlY >9a>QQ.OѦln )?1XA- 4Q;@{lr-iLw,jcrDCO?MG\s#n;5Y,QٌY;<[ I eFXm 4Jħ\xĵW.!Ymע]ܐKМqLա}Dga h\֡]&Bnl|%Fq E :4kv{aJ] d *.!w hcBD{m%ڡ^k(!2dK4GsQs+ oW~{me* endstream endobj 2518 0 obj << /Length 963 /Filter /FlateDecode >> stream xڵWYoF~ׯ {py̓[E$/ɕĂCR_ك)ӌ&.3|sQ:y7e=88c 8:unܘz/þ$AzJx_=]Z˴Qf}'/cZJQKYB}"1۬40UV,eO0 <6vR0FY~U+M!f~-]kt)J}GKZjI-o򀔑fx[4x1)>^9yDSb"L֙嶏5šTs8IMdmD"$ҁr2_ˌrc#I-vR8ősВh>}f~f-l'^[u#ߋyIQ_ EqDX91j@BwBP cc?fl1L_BtH +$uvfU9OC$1[[Y{P~V桪ZT=n4( uQT ,y۪=1| -[.uķBm3 p2x uV7m߇ǃU-h>J&U Bgjscx%[+Rs숍aKƜvgڝ4{K萩Y+RejNe0076p#a`& 'n+k0jP" c2ΕfW֕75t蕕 /r{&ݑpYeSW{8.eK[> stream xڝXmo6_a ,Iw؇lm YQ$ξ [Eo V2mnzu˰٧D1v%.yC,X{kfG8N v}jA,!qit ({$j435ib (ﮯ+LMLؤPQgέRi]^\ߎ$Bisʰ{G4 -pqvؑh{/}eSO:'jߌA\$pf)x&qJH{v/Jz^ 0d,|pK؄ΛJ?^(jg 1Do|>z.kK[t]8+XH vED܃tOF$+TZؗ Hć8=#3\dיn4zxЌƖJժ\fy_EZi F9qh.GaCǡ4a<ą% *=PƂsM_'8S8⒓mO$Z fƲ[LuUMgoQNe'KFj{"w@uܱNk] ZO OI0X\ca K֛<ҏsǒyQMZ`ū 8aoas $F+q,4LK  <+9YM#J;/Us/s^ CAJ8>ʕNj=^Kc|loe7˼}^</H#z7lᑀiy1 @q7|#KgE9;|x?tg>F {LZA`cnuHuP4t#^`XZ6M>a=DޫBiqP|8g pA8(? vۙ;uxQt(U]2˱Vр~`!pOo.k.G}++i˅|$ _:!,uL Wkd=:LF/HˬFM5qAS"\E˘FU1|]X}V  ᎁqVi}qZҺ6>g4cCb.U{N7a7T ohӊi dB 5QQΕ{ ”pzJ"HxE `m o2J to@ڿ:զ*y`1,cEdiP9*C7|`M}Jż~ƢSTa~]kU}XX>xT'(MU8"y DχjIY!ATX;zh:])G#Y7%4:sw@PՐ0Ǫ16A̼R2 "d@$3v jՙ9y2I\uNOkӛ\:xC 5zhK endstream endobj 2558 0 obj << /Length 855 /Filter /FlateDecode >> stream xWKs0+4 M9$qN'GLד R0pOSv!K@osW:pc&p) tX M&~8uPG:)e1Yp3=IQSj `P# TmrG57#]6U6y M[Xp`(WP2r 3$OG؞<#.BI?|q?_R1OUiТ‚dYאDxE,ëHAvv82J}6E,_M(Tt(d"a]NE͋9^fw+Q*ĘĂWl ̔*PK"YPG}1$35%uȠ' =Ue0?hfu|BRZSZŁȩϋck?0"aj1;|9s'{I=}pYLEʃeIAw_?{=8`s=*OKWEWj!H7eT>=@ͱC)!hXP>vh'; STږZ?dv> stream xX]o6}Їڀ[b=YZh ,q,Ldɓ&#%ꃶI1l)@L{ҁ;83[8B@(w<#ؙ͝ 6^eRE&ZtOng^"xP0=e;5wf=Z,h7ڎ Z|jl%+Pv')>A]68zyuvLT,'yz F?W#3{Qw2^y#phn!]v5b"ҘHq|Y5 5!0ϕ,Gu)`Oޑ2 74Ǹt)%J/T@]FPi5Ոc(NBg;ԵCcj^n"C~5s"BJ|gjEOk28'[eէ?ְHJ`жnC:~a[QdbBTG2=ZQvbba&2ߵ> stream xYY6~ϯ0d#-"ͅiPl6}IBi[,:v^(Gh,S25fFg?{GO_t$$f=þh΢Gjq?n~y*G>A/0ovl6Jomjē|H$n*I/x £8FQBգyxE1jQ_v3xJtO pPIoWyܥ:IPHzOAt͆04G4cY*X]s:uد@a2a,xi.4@ᙕ5JOQ׼*}vdg7XJ[6u+Aq;cb6|t@}iWB1)pH> fsg6K WBN@muЈaI‰O/f_)llMvi}oִ3$J<i}yZ@*Lw+"(yB,<$0QڸyvLz&\wNE&[@7^ ѓhbZ4۪0].\噺QME"u+Z]BMUW+Q H!c&:rM$`ڨfPW*_i0`)0Z~B =sjCC J<& ƤxmҢU_9 ,0J~% Cڧg& Cr 9U|[g-sQBڎ(=OO !È6&}ԕ{(ꁐ+(qD_ƽ)PVޠuQGһoߺ:9 V+[𩩣6"Hg7nq3JV^t,ɤ.>J>-”"+ M{1k\Ѐ>~˴vh>L69aoiȡDB "J0LmO,s:ݫTr#oggg_x # `[rH'wJ@uh'έug.?䥐)  ǧ ̊P‡hɕ*R.O|^6"]'5 =SCG Oc4OW'S&sQڟm)Y?6\{hthO"YhU ƴ"'hjGJ[j:bI14dI} Ʊ#q@7oD7AB(@x Tzx#]#~qnh}'[)k 1?v;cmˬVھcs8߾~7I&i`Xse |zXcqc9}_g]K]^tǁg6|y_(- endstream endobj 2616 0 obj << /Length 745 /Filter /FlateDecode >> stream xV[k0~B\*ɒluOk(lM!kñ3wK9JjiG(]\g$Je͚J/}"$C> stream xZKsW(AXYWU.RMZȍV;}J|+⒳0rR93~|36QF@<˯UʯS"%'wp+{<8|֨R!`k[Y"hTd,jJJF eri2#E e!5,90cPS׳`X5\,*g<Tp$k@s2" s$#\2"੏v/Bn 5aW5ջHjENΥcY+UB9$y>89TfsG8MVPLP(*ZP\d Ȅͅ` VT9,Lqv8{ P8/ bTHe f#B. }rzlb*%奠8t'z@05#[KIEW6#2nbL*L|v*YSJ8+ J\dΰDelBX.D-l(>IJIf _Tٙ"iUv8 C9ً`* 1[\qf`y w>T?~>cL}XSV雽oŘql5L'3eM8kܯRa`r0 (罾5k~wvUWy~ZRuk^`v\HI2~9lj>nSОNFuԱI؀IDt4Ch X&^eꂯ  nYSYu?n,'3 0Fמ]On$ʏFJ 57n6{c٬äǪdi$5L%\X̿WYz9Z]Ofi;/қ7ߚT.dc IHpW:|TupOQOEȑfId/'O`L#3 3pkkBݘ6߭yJjMx.><̖N/?L{bP08@@stiPox ¡_E"Q[j71h #NFVXCZ]L f`yXHɍ FIpzr ڏ.r̕6A+PmWaj#]"hYn? %2Dpz0 }B_З+ }B_З㠈D33SFoPb$J޳H¹><-vyޝMXibi9iv69]\5.&iXAb .P_U|D-z.~x8Et|MUu er0ҔtKg~U'$T:Q[id;$e)l/P/ˢI+2(UÀOagiJRCv|wvHSf4u;̏LڸTkV: ȫ}:lnR%’TaIȱܩMT~"\O'W.넹6M?VG/6S%&S!$6N!"I;y=9[\'vsNds &*`kL_,Hp|һDh)ȫ;%=}y*`[u6;EipfD9 9B&FdKͿY_LG!!5%Du" ˋt5xV)8@ @21/t]X{\Kѳ?N_o{wNom`ĂhZiG@.i2=X=]zA?#bb=V,"|NUޡ.Av/Ņ|Ի |g|#7'#v$.MI>;@+G>W&ePϲm}$l YFA>\2jn)XF}}x1*UR*2oo endstream endobj 2659 0 obj << /Length 2014 /Filter /FlateDecode >> stream xYKs6WTe"x YśL%889P",1EA~YCK- 6 >\R$m(%"A")f?}2])bN$s̚j]eE^E= Hx}. H w7Ҡɟ,c$[#JMEaȈ X汹r=@I^Z"#ޘ'pec\ nT:G6H,2r$ީ.GIX5-lmNfʨ:*ɕ NJ]bZ-e-kx9S#if1Ɛ/4<+_UuNX5J]ͫ\ՃT]ҧUE)4K!b)]*\5>G_+]d8H:f"[*xgyLž1xP qaɡ^?#)@42e \|Ui Gù2 t?۫jFaWﰁ4~\&tYX.k`DŽvܔ&, I#,2_.KYbe6o^k(( ~whJFκwuW~Q$Ɉ$q{]1\U ukb~_uw.,iBߩ[$h a y: o^w)`i_*L|@Z _s(U2_/6۾,E1a#gqWb_xg\~ ɪiY2Kƭhpy3tb,~2{ ӧj OU.ߨW(WaϺ9g:17F&;^YY#ѧՃ@9kUd+G|ÕwsIp<Φ97ch}_Vnnx gknv;( N!`GL6~D:}$t␢P%ip#ҷ\4լNn-8Ԓ->a?|vv '"f_KmW= Fs%>B;j \zꂱc@^ e=1]_ٙ/3]/b-˚fHV(Ȃ/x9],f }CFjA,\NZ)cȢnnΗԔ!G1c{&fT# nBo2$="a3T Ra4u}>4/SFO\s?SrC<}sGL+t3gNEE3KIЫo9ko0wS\@vN8Ϟv %t?L%bȓƐPs%xe^,꧕V_3MUD Cy`@Ylh#R|Kh -:{\;R{S`#$ > stream xڵW[o6~ %ś=e:pmqA[,y~,Ά ЉD["~zXX`%R`bڠ9VibŧջWoe*'6wvGfj׌H=Rh"h!#Ng nkDy?J)°Nh$@C:bKO1vR3~:XRw(<HjeP*½rCE[(vjQ$, A" H$RNgv1ϏlPVN`nb߮tKk/Bu,Pz:䩖 W|d*?iyuYM)A'vhJ6;Pp*>yCQXK]^v3uQ/.r>9X}WSQ{7+p&1cEWg &'T?vҺӂ-5xnB_p|ݼm'{6:賺qϭ) `IPGstD`!u@Sl [vA ԏsR;8Ru:Q+3 Y1Z3i䶼vF5q -} %]7=y ! $6 Vgrs>A_:s ⓞ=XnV7e ^ es%DcxإjT4_Jo˸+Ss(^ .Ls.wLIi˜ݕO/!qQCH(f̗PRBf]m3?"* &"~BnsBB'TFNzS=jѦ[3 RԢ"m>V]c~`EvBQq$cz"*mI-(=1MTnqxV9vDCȸQ&&PLa<~_hW"?kF/ a6/79Zv.l)phj>-@F r9>t endstream endobj 2690 0 obj << /Length 1359 /Filter /FlateDecode >> stream xڵXo6B@&İjwf"2W=\JJ;,)e TxN`E9 fNbxlK .6^DCV  cZF$/Eq7͓Vw<| 9B}Dvpʁ#;k`;o3B8)kQrE+. % H-`֨(Q:t&a#ZgN84*G2v\83n$Dcs5_`lvɗXm2ӻflK.e#R^*)D+"Zw5$ӬM?U%+7nCWk.?]bE=ČOh}]%Hxj> >՞j)(uH BvJK%J`A oy.W/VeR}2wVtRã܏Bp8i=O&=/i37$x*H!vLˤL- ,Ԕٷ5ߎ/gUAroxYyז\g;xYfM}Bʬd ({|;}` VYWm5MËC3t YfsUw, Rgw3Qڐd@f2l}Ũ#ddU Za۵tWr?5$]N<ϷH/P}| sYWo(r`hMf<M^d7d!EqvHolZUlj3`0B]MRJ袅I1E蚪Zy+\ <7E:nL8lT3CcP"mأ=Wmv*,zp}\usۭԋG_;g'FjӦ2{=mJBU,kMCybObxLYy$az"ft^R!Y X[n;կp4og7Ao-uK[jGCa|_?.(2Tkba6n|qxP̱˷TvjcO0Eڃq?nJ:) ++Gsm]m endstream endobj 2704 0 obj << /Length 926 /Filter /FlateDecode >> stream xWێ6}W@Đ <,-v6 KW %:_J/AIqș9g++(/FƄFLspi]udX^vz7? sw #n>)!ND sqrr{@o3 6!#+0w8v`~ qLP083%0"l@$Z*( lF'*Dc;}fXׅFXRsH?Gwa=BQ%svc}/{90+0Lo$hx.+!g|8Z t)ttlTg_6pbS%)\vPPɥ6=GMB43ZoIٍ/gĝ9`IdcF],zROeV^7WWjW=A!$S "J%myT2֦f{ja{" IwPCWѣi לb?R?XC9Qk2r7)o!f\*e[~(G |pЛi_V-jGf7C7rL G.5.Dƥ*.?kYw.(u.Yr2zqo2=vϺjɼx6vE~M^+HZ%/qp'&͋~~HԲJK?5^ lvC绷oxywȋ#}touV YcIO= endstream endobj 2629 0 obj << /Type /ObjStm /N 100 /First 974 /Length 2234 /Filter /FlateDecode >> stream xZn}Wc;TZƀ&ű,Hsɖ%4й /dLME`2|;o/7ʹ$)IV.(X"kG.pRlE:ر^Y-$o!$X1 qy =NQ$R6:30p93FP+r/ 0a(*o rH^y2.L2L)121J)V( ")S(.H6I^sE"~-oŁ(f8*樬0:.87S`J*  ^a &˰/AE.@4r يJѰL;{ѪT,cDb(0QŌW&\ȼnB¬3.bLIPG"1<  cem +F''`16_-oT}u O{H[~DAKnфSzƆӉ?Yܨ5>~ XYqEDS}MP.`o󪻺h7j?F 7höZ2@Gvݮ6+{{&FIax;N%kV0"~x`tM$Mlӡ*pBbRNjeZjeZjeZjeZ<_3_ܾڔgojڮOO&\Ȓ\a1#`R#'Je`^;J{\"B^t Kxn~002{MX'\q:[۫PRUi?&wt4ͦ- ӗmrVK1`,uyW|3j`9h+'0 ө$pyL VêF1 lp" B{!aYgTR(XD $Eϧ\vlRC`=f ~gfȨE"廃(RLw\8lŲY3e29yvy{wi\^fWvVǣuo7n.m}ܟ$vqyjMkpD~0[+(?p tp})Ʊ6(A Na:0˲Yj}hWo$aO 9a]s%DS@ϺWv38॑;t| {bӫ^@lba7BFsĖ&)Y8T89A\͛du]ZSt%t0wPu}o݆Iр&78ZKn`|9qH|~h}Ad3H!~,)>HCgis$|ݡ'Chdf_NJߔ)McȝMʵ+>vAGC}Loܜ Y;"?,E?= ="TM:hr!_~H$fX (!&ǤO$s+FNg_~N{0gCpr\Ұqb =[v8lv8qa3n? 1|g`;p퀺-G[`(& !{jLZsm:|_J~abܑ~_ 5cjWS4/w{ҬJPYÊM5 yw_nh[MKwm8ijK-lIS=;!F?٣DqQ'Imd=OmEAG: aF}}F2&;el4^f3J &X' > stream xڽYMs6WhJ3oi/ii3iV:$9lH⸿IHI0L{}0݌d#r4rHbaL0|rz4_e"auG*1ӕoEf?:\g72S>7wM%wO7k_'kdMԔT>kY޽Қ#g8Q 6%Z#*4B7#8sh)*VOE:!x|Y8oS}v0qBJ,~y6Rn&v;@³>blFk5]4P1`2Ga^yĹac!L536܄<165Y`aTЦs,̟ XSPضCc; 4?LQfvUr:>Rn c^taӹ^& :piȒwg?K~bspeIr?ϫϸs\ݞwgaa+Fk)<XCh:R깥~\|] d}vVk~Dډ\h[S$ef)<;OG@5=@֠OruLB]bۙSœL?z{`59l+ĂB^6@f(}v D{Qܹg آoG KNUvkxnC@3lc^&I_nY6KAbxoer.6tvk&&5}ZB'50kfSSU smRFd:V y_|[_hIDILmYW@ lѕ>g U{^:V"xϥ`NJFY4^1NF۷^e#L`5;Wm dgftNvʆ Aė$D($9RE/;6|`jݘ|Uv2Dhu7&΢$*<{[&qLBIwyCs=<۬Vazߔ(N5/J*N껉,_$ˎvfCeU|P&P@۵&. !EHM H RJ3qղ&I5p&dCSSN. :;%{}Dig=AuVWKx wYM'g70)IV<`$O{62qwe lBd3K&%dݲi͢& ЃڇLKf~D0%+/J(;+2B읿~#*(۪uúQ@8=8\F ^ z@|CJ#*kb(8bSH)}jq`G2T{ߚ޼?Xso 'iJo]KCL'0 s%>^a;׳ڒ endstream endobj 2753 0 obj << /Length 1866 /Filter /FlateDecode >> stream xYr6}WQ axk73n3Mvfq@IŖ"TB(v{pvƓ ?2d & 1L#rr7&edW^xQR;r~eq8+tdcc;3~g%-AT۾yD3Xbf3H m6&Pga(igՏQ`o)tFÌS_bQڶvƙ-3G7}TE_f>A3a|M< E/؀iQ yS͕?&'(bԓ84#/wnF-(X5Z6e ̋\2W΋,A4P?#)0"lH93._f'c G@ cC6YllshDFW)~/f$J A bD1oBb{+@I.QLs3<`>0GPCRnt/4UΥ )5n KJ;hxzrw0L 9ѬL:=~K!a(EB?i$VIJ%Ѡ ! hϽ{cxE!TDp>_II8_qؚg0zu?5?65Q7;x SAs6nN^!F4tİ=U)m# W|u2)7F\$vvL!ʪȕ%6r 63 V5MW.hNtӄv+]H#,ܡ-x_ WK\F}^WW}&I6.͗p,JE-bv"6SS\#Nb[rX^m#Qa2,eWjÆFsqt)h'aל5N{7rBVb̨.0Sܘ҉TCuA_ma ’nWGAW7]OzD0 g/S2.-b[%o\Ju Ӯ T /2@,QJ(l0k !H3bmo*UV-4sJf4&vU3J7[4"5ÌT=|${jp.$ib!L40)DJ~yc2wR8+ۤH(:V!!u_/I$ h7>^Օb@1"ZwXy̦:}$L(0pwpvrCTwiGo憭4ej$>}1s~`̧q_=Zߟo-P# endstream endobj 2778 0 obj << /Length 1541 /Filter /FlateDecode >> stream xڽXIoFWHPh4d6));$J#-E˥oR"M˒:l`O^,HP" Η1.Hb$ γSH0}9uI"Ev,j {W' q@S0bs 2X|Rv&3h|W$0G47`g)JbIufNT0-ݸbR2dqrd t RHxYE_6yU$J24e)F$e?7gF Iُ:]IлL M1=sF5*s(Rp$6ݖ5ގx{(ѾksEA;. |sǬ.^;{Vzԯ!>r Nݨ{M nF?pHi^. GR;F ?բY$ԜDO/%5.,ESL^Y+GhUjͥ*a){Dh$,Z}iHzgiU]y7&p̴ujEjkړ1 {b[zAK.RCykT MJrV+j#:@7ˉX Mňɤn&uJWxyt^L"t9 n6rua,ĩ57mXkW' OKի ^ mn<y̭cQu^j8|)HR8soZuJW_) Ó2`tIy2bx$ n FWMEN@[i Y3#c*:@z@LFʘ}K(V@0b$ śԀ뵪m\2#P(;v۔Ys6mlôK sbR6ܦX")} ȓ>[ Yc\-JGmuʪ&-̈gY[A JWZ 7'?$̗n,B5[jVbnNܴDeRISzɄ+nAN}|mr.LA[m[GA(vaW˰eTowlF k my(6w06a3#ZxwCD1oRߟNevd҇-vȞ0߽g1A,Z.Sh ̰\Ty~&l7O6H'f g 5.Mk^K^Q)l쵢iϔ4^<+xe1"M750ffFDgys;"Ӑ0f1`½w4o&)'Xv E۔fQ> Ӏ]u݃'xsDŨVP-wU "|+,}wń}-poF^&4Uhxh"L~:φ8nŨBa.A&oCx'}/87<^pc< endstream endobj 2808 0 obj << /Length 2289 /Filter /FlateDecode >> stream xڽY[۸~ϯ0f 3`h"X,I_mVW#yuI2/=C;LPEwl7݋$V\3F))n38YZJwy߈X0DQuD`7^ۗjǁ LGyR*1%1d0t)@XRBDr,V yR7 #j* f?yϳw.G`j8±u{xG9Rщ|of nzkᢻ6ץqJWt|)4&òqǎXD9ǝ70&2Ӧj̚A^˪NMRnʄ}XX/*9\6(+v`CmăxnzXdrʾ3Yȼv%/B^7]Em첍Ba"lI^ a_Ⱥy" yEQ۲5Fh&}\Np.|$Y4)vnG ±0e|DBdT=_}Pv2q\"-5z>_.`yI5A;ʥYS+ߐ>toV]zm|ll1㨘"!Dq@o*wc2J07&ׯ5uWڧEO>?+D=gAH:_ <}IDn]3FWc(T4ޱ/hN]%UK!\I$F6Kp 5zIe:ne8Sz 0,UqvQԓ$+^Lk,#NE^'i(wTnp5v\`0B&cOڋ)"eogoNf4Bݘ쮝x9$DM%Lt™L AdtY>5U (HhM=[yqN5 Hņ=$_BǸs1ٴeXA f˫Y Hw赋NPJ91/erᤗ>MZYzIKBg󯎵2S}t_p\@G$Dڃ(3uX핟pÛdMWz[c,##!̅,mTſZ۞>FCڄ*aL0/I#`>,^;7tҖN6'b p@N$]ڄV2벸w.x ip^;n;}";NyMZ?,ex?pY)#ҟŸ?T1=I<-]IP8;QTل?R@Yxo؏OۨuӗWpy=xլAQzs=u endstream endobj 2721 0 obj << /Type /ObjStm /N 100 /First 985 /Length 2509 /Filter /FlateDecode >> stream xZMs7WhזZ^{]VRS49.k JC%i0ƛF&*\4IqcVhd`M,L"j Dֲ"WPbD+IyS^Q>q*hvb(R\P8EQR.c.RQՖE`E=AK n?E3TFG\Ŕ#栨X<8eR͌Ӝ^,@b`b&El,}AQr2GEcXߊ#gDF1%׳b_{ht(sx1/YbU#~K&cˊ6,haRQ4*,`)rGA 戄b*\zLIV91Ee ά)@N'N#1C"ņpIJIF ^  $xQgS T ʾ . {DtTF,Y \WN|]t'w6p 2'`I1L I$$!jO,tpxx0ze>R翸d4 tKcQbv֫C5z.Y\uy,) RG j ~g^ѯϞSEs0z ͬ`FGM.gM,"5'ul(%':7o<傋K'Y %^-Nrd`c;?oefc[N ̊LQ푌fܓbWj}*,ɣ3,ֹV*THٚ^ua݄=-p7ijgn 3WqgM<}&MZ|&d LVWT\B:HuWj檙fj檙fjfH׶dumHrk𲍮y;^L']7|hBh C}t>.p6 Q#4 5ڍ~jE`g+ 1a@B;bU 8&Eӿ| $bVJ53zB6"{#e ̻Ŵ=OBldo~'nx rXcFClHؔ2R(:0oOEDqA@*OqǍ('IK%)6 w n ד[4O[L1fqpT4V5` s QW0BY[utH+稙7])kHA漙c.NEfЍ Fzh>cQ%=H]w:Sq1_ŐMQn YrUu$S YvV@c ,g'ƭ# 1\#Ц]^w&H紣f.-ݥ0000000ڊڊڊŪ9V%gSI.<pS0ōn9p%q -j Gcur;YSrPCX2[,/??7!ISVPYvq㖦k0xt]xz9 E:oȻJy(Ax]Q`b2Jy B:iPlTJkyhd3U*LlJ6s%\fd3W\594^j`~hl4Q^% o~<6zAcxA/d4%?ٟ >G4C*cZ܃p{%ipQp8H B,l9 lk`'}o ^ѤFYe] 4{V>f"Y1=ds=9<,3v6z5=Fx}Bu;}C]̛?lP͑Qt B&G\CPBuCxv>mɣd10!7Pފf c_]-5&oiR.['%6_&8hc!ѨR>Zxu3BVt+u=$Lk$ewr2PbY>K^a3Z= wn-N= u׌6@vFCݤp;AN endstream endobj 2819 0 obj << /Length 787 /Filter /FlateDecode >> stream xVM0WXZxmv@@ R!omMIn‚ĥ{3o&F` tήx$p0!R" $`ňFgWQh1 iOީ2>V;t~t1k@1p@b| _R{4c ;W6WK: D%D7>Q-K>׺n9(JuF=ItTpnέw6rk* !)pu#-uLB& ]t^ak^o^KEt k 7U8"! Pc݊swm"\엽!ԅg `$D?tkI8x7hBDiuU]LO:Y-B )P2EGBlaK=Yl^n_dtyè;^, k"nrEI8;"Uv7ː+6T\.3h'8X> JnZ+nڢmՔAWKO-Q]]>t>3Ng@ }} ]vBWc3΍*8WV֢Ɖgf%-8IoEfжhԘJ8zFgϒjwP #AK תI:2;2m'nҘAl> stream xW[o6~%)vyȺfXX% Yf~ɒx[`%߹|"-=1r, ł # /z jJTd3|LteX0FsP`iii5#x+V=3ƺ GOb^8j GQtSERWP;9$x?Pe JvSoݶJ R[RVi6݉G8Q6=i#6}`6o'PU>$A"ү\va8=/ kp(j *g3|`W®2R!mL[wgxsX@;ֈ> |BP̹=Į&I p~яmfADj!*O$F3h/dYD( >BmZMCJ0ᾬoE^eM3A b,$EaȖA1p/e{?6pkuHnCơ#֭cr2UvHp S`e.WA濹|P-\DpZLͷoAyh1 bȴ)w1jAQ#9dpA'aЖF̹Yc6 !zj/rQwSIuVaN[]NTRlr{6/g>xz[F `Q+zamt~ _Ǽ=Np5>a 1 eQSP}x~6odRU}([ehh60 9 @9"z8C Ko=eSV0f'7?JzLks1mi baCVZ˿ܩz0umic4fl|n;&3`}IY8T3/34W1*b@NB7'zMY >uvx$r-$5,B1kH˄e])g- NG*|v8vQDG'$A|t X& 5p!G-.:.qQmnYq0, Ȧ 0V Y-L1C.~2@KЛǤXR?Fp`mمk*/_ϋUWՋN_\_kˇI nC5~J,ҍʉhY , endstream endobj 2875 0 obj << /Length 1048 /Filter /FlateDecode >> stream xX[o6~ aٺ +kܾ}P,QK&iw$J$˱04E~戠GLGo.G["JB!iǔ7 6 ؔnnR68MG(L [Ʊ͖EO֠%b-8jW-;vѴE(lnxl)iiWŹI$+?B )+RG`=d(7EJ#޺tY^Lؚ&Ԡlöt0ӘkHùEբMGGW&$d|t:u'E;K]M|w11O VJtODognHg?xlK~y2d<,*Kd;:r(nY}6(j~& >$7:;d1 0Q yn+lQ .}> stream xX[OF~ϯM$2sq>Ruv}~*)ɝ@P!]dJ9uUNڳBxAOʳ HRq8:W1RO>*)$TbNasqUd;dBgt*-8 <.u,n>''C $>n5LV F`]\ /T`EAZcF_H `\E\l7=!M+;fVo)PAyELvvtTm+B^X([ռL,Ѿ."px޳`}c}p߷7{7r3殮׸{MPI- ,BoSJm3%Cne44k$ڑng0=uzLb]>};;ƌD.&R,NOf#-PDH\sN ji˱m9)cG'?~ R)G50!lєtnF]33 ;Xͳ4O@N?ٷLl.oSﶆEo3rX{>~O0.mO$MPýU֜]9 };ߛkoR_Q8jȍ0t/0əjI!^eu㴾) tY۰ #rMoٳ@WT.*7*d}yo޷'O=LN=ޘSxɔAE` VpDo> stream xڵWo4E$H_Rmh x2AֺmPڌ$;iҗvmSUqw|M~#bs> v4WnG?IFK69TAq!FGKfz]p ^p|{8qj/:u (r@eƒiVQ im =:c^ lSNV]5Γ)7YiKV>?!Ц; mL|K -N|Ip%: M%PLW#f"Z<7G w?eo~څn xAWnK];5FuVQdSdܚbrlϋC^D؄v>aR!Du1͓Ҕ}7nӂ">[C/~ن᱅(v9\.!DGs9֎ T6 7Qa^fp_όf@ũ}Vt>vǩ7 2O8\\^$ dҶ}M*ʠh2v~|KW5fj HI-N͢879`+k;xγk_5dnvHC4f}MʥnJ)ʛ<`@qSz7WTzPW;[ endstream endobj 2815 0 obj << /Type /ObjStm /N 100 /First 967 /Length 2086 /Filter /FlateDecode >> stream xZo7~_ !CHZE '0ںDwXr %v,[fE;;$?gp+%\Ď NWGR`<XD.iɄ)M EIv[kqRlX\ּX\UkM).'GA2z&q:J䈣MQ z%Ď*WMIIS5 /[` Ƌm~je#`J4d%B', Al..Ej}TH5[fСZrkaR]` lʐL cjc{=+XPm zV0*AU D7`9L+Sˌ%Bl@KF(ͶwTHmX\Z@ +f@daԬm5: 5HJ5 “$S Ф<6Eu%IpB\Im0%` #ۚ])Xve 7( $Fau1B+I$ $dˣΞ bUfV YD)-8`6HD:pɋkw-;spub0ɷ>M">`*, 7}c+Ҧm{cT$67p57fyvvn7nnz9^>'Wv~^Y.Pk?Wۛjڳ旋wycEW}f70zgfR|\JL0D[ji yKcHKÔs@ ô}=UN5/"B4LCm[{"у{G7ƈ0536}y}Dm[!v!ukUP[C6=1a2}{dr~ӦO0}uNf~bVxK1ȻRm޺ߗ\~}? WF5J2$`Xؾȗj|}6pR0ʏTx^ܡaefjZSƗ:Lg͏jqXh'⍵#8\ qpf>[/zѝI< rF :ۃ x:PxH? | (wi@.Ə*\vP=aKziKb>œqe40L%N=YڂI,Wc,!p:tWH jI( Rq6ḄMSЁډvvDl@@HVPdd&{3].wF;˝3:\Q:W޳d )o\}HXV1[dG;-';i&TDƄS:N7Hl`hm)#(L'cZI r9Q:#5#.۠X0>wP֛Gc6cBi%J4=j3fdUuYqqp`;0hs܌VXAC#;t^|:_^Y{^77D_Fр@LQHM(|㻯|wpЖIGp3-jcςi'$QQ o8tu|9˿ѡ95GlR:wsGQ:w,;K玵ѭFv";5W{9ٜ\1A ׄjOvrfo#xN޶4I@>n?Sj|l,v~]+TH5XN&  90FG>QCSs=fÚNGAI"9:z}BQ2l? Oۛ٘vꨈs&_ͯVV1eodhBhOihbP/ga$F҇eV}Io4WӛYMvVS;jFvz/Atw2zb"_{J=6"N?lNQҡS]Ba A]5A8:&Kj< ɎɤTo$Aj—B}<\i4 endstream endobj 2926 0 obj << /Length 1308 /Filter /FlateDecode >> stream xڽWo6~_a[ M! :ld}waZD!_4Kb?gOlf!Af]p0%$OCB:lqC &/}Q/ Ϲ=$K?1hrEnl(z#[ a iZ`kV販Pn$}juF3RU'ѓ[Is{hU򈼏"G9z aIn!dټFY)1uu1.34GkkE\ˮ5֨K rW*ksitb%yiɆleomB70ǭJVu* ϑ8"qIVN50 RRE]άu4#^:0&0c"$,+n QU>vjvCP8[pȭ&B ۮ.,eitxȟ(y(6q?%JMmiI,( I+R+D]͙s7 b޵FP 5^-b@)PHI 7d_<: eB-0 k܎B5'ǍrnOҝF|ϭ)Tx,v? XjP}dDQ4 r0I+K%_XLo2B;шbMk,A 8^J]$+FcC-t45zj?FcRא213tĚN:4P;c+OЋ궹sv;ksţ1˒GPS?N)+9٠픽7JolI+Y64|2y_:H%$igK%G<n8"и! |LTf;&w_3'?@ 6];J„KxrN!nj+f{ ?qlvjNoS9zh NSEQHem,[|6\t83Ig|AxsĀogCB endstream endobj 2935 0 obj << /Length 751 /Filter /FlateDecode >> stream xVKO0ﯰ%Əĉ+@UġU c 8f%Хz8OoqZ">/fG#`-%sO@s :s(ex(r1uN$jIV6v 8f!Cq>; (c[2D5G88:}y8xސ%XxRΑN=1-} )EwsP4,\[B0Tcj0З \ugF@깙S{XnuK3~û(_e] H{{Q8U[}"cUIrYw,/-A}y> stream xVKo0 Wa %akŰ-vAuăgǿ-9N0d")~ A#Di}up1$@!`! P_;Ҷ.LO;äYSJ.9~(U|hIꚠ#81s)g gu 8_A HUKW,crmdCIpڳ0/&.62‚txDPgAHgv [HuX[mŵK #HFtc3WQU$$OطnHHc :ZQÒz}oc;v d#k8~Mj fylCz,wR.1hPhφ!GZo Fy"T U4ՑWlwx];ꁗm^b0N]`gN2m1|#wtv3I~ʲE5g!{C>o4,3/Xg?>xV6а=NaaUZl(T Li: E0xEy1 R)YjWC(UvWg &L8 KR>_n`4G,aܖ澧˝wbctT,%m77#hzh`E'v?<"@\uT)󟏗աڔ;R[E?};E}]$/hmm$7{zy֏MK7PV5_ ƃnj3Vs?rFA͐6U4<]>j;7 endstream endobj 2965 0 obj << /Length 1415 /Filter /FlateDecode >> stream xڝWYo8~Ї)@mmm],EKKV+Iwxɒ#'vs缙_$$sp!Nz(s9.te'c8F]pn䡾xL.7%Z1_R5vf8A85z}%1_T {I3sqCDX_G ;#5gFJ[b#'/ r{#4P) E]әnU56qYYlhyv6QdtB I Τ޽T - ,ѯZ|f|!mmWM=%{/4%$O@GaD%A񦩛'! PA~t*\o悷& JzWs12?.D^W'v\\S;ng p BGYy1zM)WחM' ¥mʫ gj740(u\!Y%vv$ܙztl$(EOw]p&n9䇱7Zfɶ#j}xKѽ|~^,wsxZ鸯tLN:~Éh[^3&VV M9 Z-Ceە*Mb]t1:( |rͫ;ޜPٯ) =]Zr#x>%Aqf٣0ZJ`u "D]8'Q'ZRKMl#1e}%X x;^!/7*[{^mFJimijgƀ]0b!L]-0GQvDG)K:uN$+C0Y eZljHgk5d>[*-6Y');=;dF!Ȫ.L;-,@ F\`CW[tT6[zu(&eLqB^OC~g=U:57(D}`0>bNWt 27J)vĠit&V2"JHmjyz!$GE}v?P;'+gO{k+yfcUqh#q:i99|ν"-PD]8דFP i;$>拢5@֭.m bD),yE+׏s(77]ySLv擠$ؒØ~Bȵג:{UWUɦg DQ_FǰT^i\6$zb,%> stream xڽXmo6_z'-kۘjVN&M,Mc 'i";y9.vVvG?FW(T8{`<&_`=̖N84ϣ>~mz/VRRpԴE.4&Wupb-t\ O>χmA}Ik9iE H:bQ77%@3/k݃Z{ \"&ڨK9o͚D/*3eTDfWlͺREE]_ ͈̇JZ :B R][>ݒ#7E6bW\j)b~S\:,Aú ʑG ccGv9t918D>U?I}U4A_hT{:D2Z~3_< vЎx/q.51ihQlT.O F4h"t\/1|HW3$&>·#s艾`Eτ%߀k||(՝sLE*=nv &( qܘ, Owp$ [ƛmKe@NaXO|Tb$.?ly2;;IaoiOfY k 3:0x M\wwŗ|%I}eMARZOzSqC*Vzk ?S:jǃFưO+U,GXu/vS:{YÈ+ȜJgdq@% endstream endobj 2923 0 obj << /Type /ObjStm /N 100 /First 980 /Length 1850 /Filter /FlateDecode >> stream xYn7}WE! Anp[ m'Z*[D,,_UNEp<\ xL% HaH*)Wbd&ムGJG62>R 3Ak)c !ƧT³$ M >s@i\a0,`A!eB YqbБ#Ť#G#L$9c-1RdCح.Lהu=oF+BKt~&:M XTiv Hv`CO)WX{d dK&MUTK`*MƤ҄bJ03f\˜+Mq hã:)49A4ZsEw!H]!"% €%R_,{QsiN퐔a5vֳ&&KĄ}}Ry`Q k7HbSMl\&$\]hw֤X:J+~U? `Uz`w)qa#)qM×g3|4/փӣum? IJN2)|S3fRlDLhlj';AYF h5}vC#ae~[F] )Y$n`$sX uE`C{A{ׇd}b&V((j}Xiha -P伡eElB?oMS //>o/k ?i'`+-|<ꩫYmf2?^|4չ Nʄ@[K cy|{Z%uCCCM . 9|#Tz_HwPU҃ýL"w{-–tE{q-SV8 \WU-.h8 |({ݭ.5lrӫ(}Wdݫ/D޿ZviE`SknEGEtD^+=otr]ё|źdN^u-}IKK\ *UTx B Q8aq1Ȧ'lz||i$FޡILm$IhY}:^o._.e^p|M ѦԆ0iMm萓&ֳf+Q1##$H*PR9t,ws"7]>|[o i+P΅ oy;U\Kkǚp"ӋVG3Ryea t>4ng`KTmLQI_2M AEk}8IL3۷bppF+d*+xc!+eĚ!Bx6Lgۏ V_@zvIȦyzٌM_GbQ^RotxػÝݖ+mLosF.Mh؅*g>#֯|J\M&G dv2o228}? ӣU¥39ݡҼ lCK(6@ MIPRGtК7 } *ѱkZg\G6 endstream endobj 3024 0 obj << /Length 1343 /Filter /FlateDecode >> stream xڵX[o6~_:HsٶiYuUfڗ^ݭ̣|lZdYժ;ZȧCN{ʡ~Q=+lj+R?O/\kn`9$D%q_w`Ca@[{2~P`P6?;6A u.}#7n=$fءCA^hD|쉇B㡌l6s|ᇲGeΉBQIV"ZI[QnXEh/c%CQ@X+djqYPogO0(7.󓠐s`Arl_DTgЧtЏRVk1]γ]TYyu gهiÅ#j-'Pˠ?4[ Zaj]z6_> FK,Fq. {BQ'[Vwa1*l<2$[#n TW *]SEMы?4q%Cjȷ-z$RXs"-C}`A oie$zv8+/'  A¤=Q z?*!P ]Ȭ^9\&';|~Q˫zx IًۧC BMfCA}I CK' !Px͖$ &_0/d%lwhs~Eq)ۙJ,`%ް˥LnRjO4-&0O M}JM*bf۪cDQ"#5~9o}6K#}98 [0g9( V"K&U"7jFBdjuWu6Z3y߫lotzP F&$g)R5PZ5*kUՔhdK_AOJʍO^2 Q'G&a T=.`B uf{>$ՃIn-^6 endstream endobj 3042 0 obj << /Length 1040 /Filter /FlateDecode >> stream xڽWmoF_rjKaoߗ%UWEBG|M;Ug^Yl|7v5{A1G#-tV1.%1:>Z}4 bcZ"5(Qզnn]Vhi¥ϯ"yzJ9}aHz쵾>j В#%kmGqzs>0|c1<&5kf K?d ؈a@YUt 58I2l],\>wikIz]٩ ;V\zj!]#B"3~iޚ:bxY~ݣէfiQ?>G$YEMk pAjOGq`+ͭqyaLUL?ryePmy#cq))hD A<9Rtx IqQݮɜxtlDX99/u7t%IAgC!LCvY:\-\TTxmΎ gE?](uhP$.eap6(6Tnz hbzrXjrBwGfI_ zZ2 endstream endobj 3065 0 obj << /Length 1171 /Filter /FlateDecode >> stream xXnF}WH;F6vMX-P0~ŵDC\.}wxen0=sf 9 )I3qƈq#3pLH^M?=2?@T*8hbL95tLj9RʙFvbܺr8! s9Ԟ]Ko IN ą)Ri蜻(\揵w]"zzT:*]Vqn/W(URhOR$$R9NY:hmى ( ^(+4OnJ[jwC{ҎkW*H_M4׽:l'7'0_jW븲oYe̖1V+ M ogUK pS`>arR8[Ur><*N2Hwu3q_yQrl*: ہe% km6ՎǠMz+n% F[`@ٗ! $ Q on4$_B17eԥ?2=g2HYla k1Lױ Xt+[R!ls(Ǽ\AS}(W/diC>TXA_%ch忪c_e'WWqG@΢Y\>&Bszx_.j/7=IS;`ݒ[z0\ _v(g<)(3Pp Hr1pX~kqdu4dl 9Y C1y-Jgs}4"x-[&0l9cfk_};l:7 S endstream endobj 3079 0 obj << /Length 984 /Filter /FlateDecode >> stream xVo6~_A!%Q$CbCPhƦȴL?\IN~H)#V=l^w?-@rA!l,7#C86X?}8/+^.{r.Us4A&[VnT}ԛdsh\.`rV0654Y鏖^IGq7J呱,C.Whqr'!2ʍAyȅGaQ൵ɃD0po' W+i,:-"6Q 6BǢҋ.365iltSlӃjiWY?Cg\HW;(8=A69C̚! ҁRQϡi뽙C!f@3~9D_Wc$oCRL/,=ۓB@LkO :5.ƐM>J$U-=QlPiCpMbFɴ"lЩ iEMCEu1[&!¦%DѾW%TYvƯF2˜lY.;iʮXUClcSl2> ;]fF(4,:u!Mshً~r9dcaCŒmhgߏ>B8URr)G,z>B+-EMQG'(Pi)lƪK $ 1`Dj}6u Q MC·6r1"aG׿Q)Y1SA'D*yduq5z èΛ#܋;}pL~*˚| ? endstream endobj 3115 0 obj << /Length 1323 /Filter /FlateDecode >> stream xڽXQo6~%)R"!kEm7IH'Iw)ٲ[ H;;_/}ϑHwƷyw#Qg9!xt=2XDJf2Aq]Ei);ӕMҠ|g3t& ڹتq@B5FjNGGp|F.xxb+7Q#ʇ#‡*1RUf6 B #.E0F>"-vH`TpځxP Z).;P(fc5MpDJQ"};tziͲxo7!]B9bޫ0耀^clWyVz|%Q">IÅ"o`;E* g^m*#D~ßftrc]ğ'X`Q7kTvrZHN4CFYUW?6vrID\MmkCTeH p!O_o4>~ڳcrrMalT#} Ӑ9Le>kJ[lOC/?9I4L|}gXgU087S-=%n?;; endstream endobj 2997 0 obj << /Type /ObjStm /N 100 /First 983 /Length 2261 /Filter /FlateDecode >> stream xZn#+x^(*`1& I9lb;%4`e{m$խ"X,V"ۗ,ƙ|0% lDb9gR *)AT\}*EC! $6N*%C =BʆJ$.k[B`C>o2`R `"U `Đ!egRV8I l+Ql֙yHt ѳ@]ʼn?R:HJhƍD_;RELTB" ƀbX +UJ$Q(8é6RTDS݄1:ȆKQ8CsqIM U HR$ u-;t-F$wHV :^gT)]#ı(&IV3B%e $ >*{%m=&29]ZHj+PIM'bhfKIm*)Bbm!a\J C_B t'qkQ c30McGa*ErfI %`'8c)TWɛ7bc޼19ǃKp{ !Z'ӟV˫\Ogc\N?>w;`:{f2=˻UnO|s [leO6K7[ݭX,6\)vBB W;M&&&Lg+#T釻O|[թֹ]ǬN6%ٌIS L43/z5Fvc" k:8$ g_l3 Q#DKw|"'@(ۈnuc ^B;!ZxFCCҔ^4[4[^ !YM SI#K0{v3oB.ޅ-~:b5$VKr=#%Jԏe1;t@C8*zvh"P](b i|3>r#}x}iݍ#𥐑\zM ,lhՈ@`e>{rz:VX# qe~Vͻlq="dZae0jDZDBRҰCŔu:[V5J ȧm{=WrS-!+(8v9M* V um7V%C9maqj3 hKQ0ܨ=j\l}0Z$$$ x8PO?$ݹ p ynl湱ynU@Zr5%,ݣ->?]7֫*OÑ-N:L`؉/tx{.IeD#u[!Vhc%c"}W8y+1}@7cn-dT{(Ekb`̓x^N< a {[(KH ܝt)I|{'|qz $Wn>P68ӳ9m ;M0!|`ؑ8{D oG٦#G6&qsR~Ax_#>ͰU $l/JCt#= @ JJJJJҊҊҊBEiEbi=s4ڧi>MiOӨ}F4jӴqhD"Ig=AT endstream endobj 3143 0 obj << /Length 1586 /Filter /FlateDecode >> stream xYo6~_!f_b}ִhX fl Jr;dʊm9>H}ߩ[x0}2x>bD27ƈЋBFܛStY\n&^w70HJx]P p9|b4/ QNz0~ctqBPW}F!<Lv 7IrfE>iq:7?j_ jeTElFbi+CP^^B i!!A ;ϲH6O$ℙ퓥2#N+v^ɛLSAʒbt"pY^o3BA`Nm!y#Nd؍gjmW'&[xt>Ès gB BfL兟d5"y˨&պӕQSn:Tq56klqȠ*_̭&6vۧAH@a`V @wC tn^0^3 t,7s3lqa\S"8 Dڑ2ܩ!;eyHq=>5aYxN[}I':tͳͽ}([?.>jI~*k*h\څ3/d;/u*E6"PP`jIɧCE# Z8aШWC#R?WKwSUͷ Sr Jק(?GcSeNgqHbS,.UbεVB77_?yi\|A#78+r2PN endstream endobj 3159 0 obj << /Length 1072 /Filter /FlateDecode >> stream xWK6WCťHJk--6*M}"-KvH"q1vv'?,&7wu"$pQ8aOH#zx{sҀ#BBZ._Wч'w=\sI7'7os8\Xk2w\#F֫kxz/3ivLbn*?Ԭ3وD4¬M%2-mQGFN7rſיHrpx({vOڨxL7EFcqʦR̛jf]mb_WڴPM+(̾7Y;s~2Z"{&7T ahcsd 7u->!1落y<:(1[(b9K:?A&xD}@y0 ={sZEXޱS/%FU6bs&. K)_$*7ir9vY"p'&v"؞y(d3, !#`0,`8n3 qK$vڤ_}§ Ddz0Jz0+Um·HytN{^0k9xѮ"U`*=TVA i2HͭJ'gs<)]@_21 QMaFa}NuӇϟTGk䠲RDZ )Nk ORNcOӵ4"m^=fwfcE?e$":՘\T4NU`nh\{rGw|zD3HPTn˄~Z=[8L,ekejŰ9G`Zfx_)y>_Y23KXLE,!8vEb9W[NE,N`UOC Fd}60@❨D -,S(v֫C,B |[rl!(;kƏ"wM)L#i|}^> stream xXo6_t' XKNꮴw/YR$~ 49>_>_?3wǻŕdHC!1ufĝL~ǷjO݇~.!R&a+i/}*9tyB-yxyqX]I]WTHFҒENO͞ qF@TX}~R6}OD|œK1^(ϧyƳYV*b6xǯ*S"!A!֎mn)Q8lQir؝bG;G@=AL fzU6$?t2rw앜q-OV85g6ZĦ~#%3II9m b/4P(f%Qu-NPqT#jVO@ ,J`DtͿU6/|ႆV-72 8tM&˹WVQ\ڷ0Q\UU G48(5 5XEPxc eUwzBI-Wm+[Ei $972^A6UiJWliV]>c>K2pDAz*lsLj]. .h&˵GܢD{jDryw@?5׊N*&QD`K4$)76OS}]K$Dx4ޒ-׆ڕ`E栁glO619KbUeƞ{ cAtO_*:]xϴ *m|7kD B= FPoM3w@ ]Lթs;ȪY`NqH`P~`@aΪh@0I㶫;u1n.[e.퐐#N)),oH@"*mzi<͙棛sڭv {]>\"aw13Si;}^-?@d,}0v_0;9ƥ$?dG[w6`*J; P:6'Iz`ӡ;jtqANؠqJ꓀ #;B1\Ȗ5!2 D~'@^:O1 aR<{)`ÿ* endstream endobj 3124 0 obj << /Type /ObjStm /N 100 /First 995 /Length 2354 /Filter /FlateDecode >> stream xZmo_[$X̾B`Ǯnk.F2Jl$R )3{\ʪM cR @Q<7))IYY Q.*^8hRQ5Ɖ"Ee]H 6lA&_$ln?aHʑ"8DrI ?S#̀b=2e^F8IYuKE„N^â\HPƫa)d00żF2f9VD\ QQl$E)27- z/k)S(\ bY^P0 Iv6lHQQ`) 6h_0cTё  aKDf QXFdl0EeU1a3cET|ˬT `@%`|-ـwDVrAq;H\"ˈ$K)BeL%,M$znH r(}(AT&9=&_>#cY7B,g#A IDʼnb|;! 'Ƅ.<#XM83 7D3B @),p7yrr2pӨrL_^lzެ Ҁy=/'gۼ՗W&zD6 ^~w|0*d]Ni2^93Xцvؖ9_:׃cq.]AbC},gfp@ޱD39wno=EECjIz]h67Wh(zhqhn/6vqEgy>m淗Ƣ@Hp;Gbю HJ"c#},W79qN/ ͱl.f>_, x xLmp;4UBkbynfۦ.J 8+vxƹ2) 5 B'1 lsIn0<6Kwgmj#G)1%0Ķ:C3gnJJƚbB^RRRZNrST-j9U˹Zrs\-j9W˹Z;Θ*AyIqOErH)4k# oOf-?dۣpQˏ{Pw meQt!`fa-e`灷~\=tA~"2ZrKC¤cgұZ,Wc*u9KW1UAFcؑ;*{ṭV 2cP~gƎɌUTf?c2cKez`1c]>nj/Uk endstream endobj 3231 0 obj << /Length 1057 /Filter /FlateDecode >> stream xڽW[o6~Z坢om E5n_`Sl&ٙDI6mY9w>~]Ji%##ƥ$FQof#B=Rme d@Quh&ya:o@@٨Iy:]co?~'zO KՉw5շV9O@9'I*C2ʹGICsb2?GET$#5FT@:v8] {ϳ+ (A8cZX!ov EMnPPjc *GKӉbToxt욚n:CIm Ո~0c?`s[o7nq)"7 7r,fqB6;T(6Oqq͒ [}8ȧP># n&$q^P)@^:m&I>'muW Ћ) x/zxU,Wڰ]:P(&`t뇈n`a{lؓ) SY X`'u,9N5aNYk 3H$k3jv]{8=IkyC)?<|(L^dKsi ̅z->g;` * P=?> stream xW[o6~ bl] ـ-^<6㨓LHd˒]_aCs\u#> ~޾lSh(! "Xr34^, _w?ھύVޤ4 ƃэl&4L obRLkaݵ/6~Ji[ [6܆6|&]^2H,8MZ+0Axgi=r! Op1s>7f<~!),I,^]TmQywkbL0*\$ԍsWZĶ%!9>É3R뫨 |ƱSjpj!WH2b0˲D0^c&(W`N\+`ujP:G]1g;w 5$l$6x2ui|r/:ynJ[ il\{$h_k>-*=aVnYX6Ǟ2-C ?<ÆUīkϨബgPɖW;,-ZJHn3y}#_@6Ѝ'^@1oIV+ӈmLCjNz 2ߣrh7>+[VT M]*l67q<×!.!8E:.{aq9Z6 eo-\ή/'PLh)HVx(͹&}_Pp'iO@A (?C!549F^}%g*n h hvno:ܞ\y\J>{LbON?p}DU8wv 3Ώ6[[gz;᱇CJ}i4=|q|usp8ǡM||q0 ]±= AY@b,/|>+@Cd&~FǰƱ(,ZGE|ㇴ3ZKӚדImc1W'GT\ endstream endobj 3281 0 obj << /Length 1244 /Filter /FlateDecode >> stream xX[o6~ϯ0Mu>4^`S,V!Y_#Rw+t@!HIx.<Ƌ/ޞ>x#Eb[ba ,F`7vWr )st-_gxyg`rI^Ҵ063eR,viwi'yMJ5kiwZ GCj*' !.¼A.)<ݔe2NEf$22d߃zVI*>]w$dp2Dmv3F\= &H,ZAr *~Y8b a0Z`ʤ.36itHw &=S6qRZ&'l>lȻ|?BJIZȑMhwe!?ʤ"G+ D{7MYcjd Y~ KI=w^3Qawjo1P)D(78+dh~O]wW]g)9#=18JoKݟak㲎Vf/msIlf b &Kv?^e/<UuU`ΐ( ⯥ 1$a,QiG~z#.b~37S)rm^g!zP9S9je.5Wla'#%3!)@ j@吤XkoID1i{0A\g >?V~9\+pgssm.ԘxƠw[r%o+VtgVMYUh˧C.i \oMh% B\ ߃Z`=UA.ƛ؏myMBu0keR*8ޕ0V4W.T@^U{]I}KU-Xt>'y/f/nnEG{>\6 endstream endobj 3217 0 obj << /Type /ObjStm /N 100 /First 987 /Length 2165 /Filter /FlateDecode >> stream xZmo_-R2!!cCm5dh+Ij;d}{ "yW hvoH>!73g1 ل\bg椂77d")DUbC{v:àTb&|H*yBS2+A%}CpLPK){ DJ!RG'k Oa#mmV%(ֶPᤳUϩJ,D  Qz'E$N 1v.5: :[}m$T7d8V$Q q}ѓ^ڒV=dEqlH'M¤0Eb*I)V)$Q7e#.e {hcV<)chLFH(`BJ8Ij@f$1$_HI$g$;%h" U% [Jm&FѴN >563Y-k4S :Ot IroUKԸ aU"3s5jpsѩϱv#{{uftXnfN6ǽwY:rXO?Ϟ7;N7rdmY]|朡+3̞~e|{{r4ދ0&F`KBY_X#4d6Xp& 嚦LEP-+ջa,xʔk+jn-tLkh(4ʔhh XvDsO ?,HNSKBca Xl>mbM(v̏Ԏ> stream xڭVn@}+VMTo~BEQh_(6!T66Qîqp⠀*鍇'jی[PJR9v~u(ѧL`34W^Xx J :_joϯ((JPˆWQ. aϰ5tgc1IWy4 麢Gee2)~'e#BWVbf>=HZZ &e\Y>o|5(̃*M+1@2y$W6x{+s^dW7I*0g/+n#bai4 MR,M3fiz$; y'Aϋ ĩ m>r>4‰mµ[ßXK.0'AxV5T_J_xd,wnwwuU+@6o5([ mp+mz;`ɳ6/;`k.3*Ӡ 2? zRKi> B*/ogsH~a=!X%>Pr9߉$-  ]凷gԜʧf``88 H'FTo ,VBkrFVzsh|WtV.94=l&ۏ"9~y_qV<p]e2si: fStn<^G|Yik/J׭' WgZ[o endstream endobj 3382 0 obj << /Length 1325 /Filter /FlateDecode >> stream xZKo6WCZC:vM !- Fbz4$;CQA>0ÙfFC:x~\}#Tx7'WE=ky懋zq7o!o"lV kd]'֭0)B?I/yo5V̟z^A}vy,C'} /:yr-)ÀGVc'wqÒEZLe&id@!nNÙ/;"T| I["A{ &l;P\(~@|.Ӣ=څ!WJ[C6!` V\ !yx nζgS)G ۴hd:'<B |qQKw ,,u!=suxD)ߪ$I.T߻JJt~  P}h˴,+} -1rnb11{y(\_\wdl 7p [07hݩ9>h2+oe9U4 :@7,97sVWiG`p-cYlx [Z&Rۆb7D=688ږe7_N6i|?V%`r3U3y\fM}ԏfT~p йk:J쫠4[3]eA; MO\ `b\x\xonl6)ԏaOaaOI(OI ˉ1qn2CS%,(ꉛfSNSNg&ףn7jˤv K nݬ;y*WE#]l[L NG>c઒3&ky>ڨ~H},+S´fd?C endstream endobj 3287 0 obj << /Type /ObjStm /N 100 /First 1005 /Length 2628 /Filter /FlateDecode >> stream xڽ[KoW\8b '6!b+#f!+NHNALs>VG3R$H:(7,jԾiA-Z mOV= XPT}Ł g@ZR=%,-^Aaw_2dAm+ep@kt >r[% f+ d[Ab+laM-V=d3#v\o t2Y(IbP5<  ^D j=\⪁fܼ4)Hv8SP2sP;s\4ąЗ }5h7lpj92LCq5s(:~s(5YBi΀bKvF."}B8ZDXE ǩ8uD .:p/=ؽ𑄘v_M,*Q`O77o/n}0N Ƃ>m7+v#?r= PBg/7r,`=>Ǡ%~ۿ{}./xr W?__Cۇ{qݻx_åݝv\)]Ę&{[Mˢ/|A`_42؋O{pϋwCvv/i|y5 anLu&/𐪌}K,W?]=<xu9$͠П带XmƘ[A>Q"%_'\dCFQ6+({K?I"ZD2HL9|! \f?⻛f;(Y7$|Pdd{[kF0/0ȕg؋K>ywf[I"艻ةپ>`*#b:{lW6ˇd3+GsY_T_4_,eA`_d_829292929292;2;2;2;2;2;2;2;2;2;rvّ#gGΎ9;rvő#G.\8rqő#WG\:ruՑ#{e҉ x](ƭ1%$dU˥/Hn1!)Ji!ÝaV}]"YB;2ʊh~q`賣QǶJi.Xsǀ W²=u#~0-JPN14  ;*]R= b(Eqh&Q0['Ā‚Q6dq5)LO(QL&X#kꈎ :=^QDOFEQ "ZFN`h̓9fO'J;tD}=J M8i;8’F9|FYc b_RX*%k9:*mPƪW3F]=: iE2QhEQ^;R(V[L! fk^qxLȕCeVm/Uf>KEڸط*/Ugjy٠žF GLօqxi-=,4S(6?0,|cd{jIư%o%h216rA)esxY|Z Mm/+7/<&D{Z{˖G.S rU( I X+)g AًWlPZF(`S&]C첕iۓÉN!Q29rpd{y ~w&3:[1mjgo{xlOhgJ2^cjWling.eXflYc 35aOqr؜bGCue*9w?7熢gPN~'Gll8"ذLcCKlOƆSzkcjPn 5'**1zBC҇vΖC10Oe}蘘J31q:o ' endstream endobj 3509 0 obj << /Length 2067 /Filter /FlateDecode >> stream x[[o6~ϯ:fŋD(0IStH"N ʖ!GK"EtpQPQ`>p>ܟxCq` l0y㟿s+/D ΜR+LjG#DY yR g۞F qAk1 2qw$2v4  -1DYGbŁVHē(xB\]Uiu>>h=G/xkӉO)"+:Pz$ 8ۙ"L, K~e XO62gr:xIz+ȻCFuHeC &6S OMm\g7J aKUWa`ʩ j9-\{Æ 9m"ήʄs#QZ5:/ +% wj/;*z ll:[EeϢ[/ˁw\dD˗7]vn׬6K.)S|rt_nSwK՝ $l> stream xڽ[ˎ\Wplج`( EA EF !K9ž[ lۇu8U{+$ԒH/iP+=Q%.DRKT(.D>r1{D pIKغ Kh&뎖x Kɵ%HUu Puqo#kI %_{R=#bJFk^IG5 iY,\MfWp'kW!l_KE=RWT_AaΪ(0{Zk]s-Qs=fR8Ԥb?𮩩SVŭ%MGK|Nu>Ro.=u_HݪuPJrýDaQ|N`7հ)C-ʾ4j:Cj%Q)XCW1ݗ1ƅ0z>'&,Djx"lj .b58".cC5]b5Jb b56ElXW^ER| ] _?XMX '% F5O^ӷ߼LW~LWxLJX_}x8kÏoz5YoXf+>`튜'>'BWkCh!!!HB @<yȞB$ B!zLLLLLLLLLĹ́́́́́́́́́,,,,,,,,,,llllllllll\r 5k @\r -[ @nr ={ @9bP#5bP#5bP#5bP#5bP#5bP#5bP#5b"-b"-b"Z3<|WO~x0sSysO_!s{بdk }9WO w?#AZu3ܭFњ ިf}\$@QZA4-:(J<2j F6[XB,a5;CԖQ$!]zU yA G5TX]F۸d P_:e,FٮP `|>]E@o'pJ)Rq[_ ((p!Y@l( D^u +;i<$ K0OR^dI~QB %X],!۪f{X( L*=Gx[ቾzcc D*7|d^1QWM5T %^va 3x926 6۪n =+t"~&\WFiEWdnt9蘐;bwzޯ~,wBzqgaG+kP‹퐝>45TfHGIk+KT:*r[QRLR* ڪNVձsﯗ\%F*2{cW%dd^Vѭ1tj{PмMC[lGwDm$ae]]ض}mUw{b kEj,f4u3)qtŒnO(Bu6ovÿ–uxdH}UAs4CĸnPhpPT!YWիo&;U;'w>й·مؑO*/8U%DQj UDivgvI>>[U/ٙ#3ǥ%[YmƆC ޼!MbK(%+Kl8sMչGsO;-V}>#9{[ˍ!h"=ڹˆ`d_`V?oasU#-}_}6pO˪ڙ-}_>Y$nHQ0S)v(婪?HM\ƒ^ V/`rU3}E''|[|3sF)b5_p*:F_ ?c0pJcN' ?SS3(j(eݟP*3"CpXRO_ЎE/,j_"sUUK*otKdʫFK?Kd[RBeѡ<3uzn_ UM@uʊᡊv܇>g(ac}бSP"ëv[NhөT4&vG_Czm^Fe~MqX~Ђ 肽vL\y8Mt>,+Z=wa"y&t>~ƈTw;ļ^:M(]3_buE<)^:Z>ϽZU40 LJ4[ ˹R\Ad% _.Vf5XWmt|:yS3Ԡvn c7:Mt'Cb?p<=생ƎL>'4NC . _b3m%瑤0PɃQlCV{.Z/ % jm[0-wLJJ|!ryS ?0puI$E 2wSz)*G\.Q.>0@ endstream endobj 3682 0 obj << /Length 1824 /Filter /FlateDecode >> stream x\n6S:f3 kCM6lvي#̇RGYcQ"պNJ??|_xs!6Agnf{?yK~ p*FE޾-Yve$`d /ӯގ?8،adYF@P8@$Fx42G ŎǔaC6|LmE9g?@6/FDT39QB L :LSPD#@ αLˑc )U4O+ , 9 Ν^jD"ʝ$K@ƑhsjCi@2(!RJb=4oZ)XWƈWe'9 .^DD2K;*EI7C'oL7sgs0{ܙq*|nDc#I'9 .]+Jzґ[^RRW: Tg˟5j%}mwZȰ_-&K '`q.sLIB`/RR99LYS aY7-U npsJ3sY=.M8=OcV"W܇ܺ4V:zf9||*5OVr;'+ɚ D @ZXUZo26 Y/j6QE<5O}dPIi(UI_y~җ!N ^aZѵ%%$5s^T%*6`oppHr?+GL bz@L@PG BI䁗24O-s1 5ûO H]S)LSF#یE`O*O7?oU`m[ lOjdx(Y NvZAۻN}}Zfg&/b}W"ѫWR,Q *4%*F%}y`!1-oh:HI9"WS~=RFA< &ŢWFV,K8gOA?[ e\ؒ(y&ڳS\ˇEY1eFe{!ۏqqg. Az2iJ}锰aIqA[P5hhɁNmqu_<2k/:OQ<|*4!uXzNE)J7(,x !/z޷@Ϩ{k f{# ڨ <&k^179@M!\O ɫi>O/V#kQ&0eDTk`vN!uoݟ{A ̡ ~*X8A#FK%6kԆFD?jJ^y8JM~TzKZq \v,P+galJd !ytncGˈzxD/6jwͷPrӾw\r'9 endstream endobj 3511 0 obj << /Type /ObjStm /N 100 /First 1025 /Length 2726 /Filter /FlateDecode >> stream xڽ[M1pXŪ" l J$`DAcY4=n 3XXEtJ%U霨Voּ!I yCV%zYiOD QwhCpYD<:$Q[/]Kxtx%꽏M5W\ JwhؚwZ *G˳k->ֆ iYRb8)hIRelb*ԒrԓuhK\Voq2 }pMdd]'4XeK֫-5^Z]呚.Y͖~a!X*Swk`\{eFWV=",%\Jg+!^4VVih51H]`܉;|RnTd T{G`J[栲ݨN@ހި..>k6Fݓ]YEoL+9.X;'ƍ0]5cDhY:zkՅDoVVۊ YCoR 5wo7?o"݋w7>}xx|w˿?/N=~ۂ Qޝz|;psz+Cԗ ?^Q2Imߦ/ttzgٟ7 $:gxƅy ǢVz.%lD4=+,Ld[d##b-ZIjn`æyt: I LydpHi"~nh7 $&0g7U2#hGCj˘/$ddrR{$HWa+I4G7XDPGD h-, fU $34^n}DBb6t \-=ܢ \ D{)H=Yt P` ݥ@3](%DEt#fB2KPɄDpĘ2hK7 AOr` d+%*j93Rx􂶕Cuz5rL<6#d/ro|T Ҽ2#* dW'~ U3!^1F\Dhf?@N?_SfTR_~] > AQXPa.1./;T^|=~W:~*9^{W/؟w|z]YϿQ"{OG+q5 vsF87D5k @\r 5k K K K K K K K K K K k k k k k k k k k k [ [ [ [ [ [ [ [ [ [ @nr -[ @nr={ @#G @<yqFesѨѐhh4,-=LLР-4hA ZhBР-4hA ZhBР-4hA ZhBР-4hA ZhBР-4hA ZhBР-4hA ZhBР-4hA ZhBР-4hA ZhBР5n.&Y7/]ufFDq`DM $Du0#j_-Q&wA4Eoa1Ѝbc>&[Uյ ;XDe1"V_eIeKL;]SU<4Ixu> jFrhkM^O5Ff|b&SVP?rOLT@3n`1s#Z5K1Lgln)[ez/HD%!ϐHHH$" ϐHHH9@3ܷ/HD˂R`qNI)[yW,]hfip?5`.ԚQ۱(p$* ,ZUe=j"XϨrala$t,"^VxD׃վ'QAԲo 5:f:H`Z.$L.$y 9DH%"T>v*o 9 ́]}IX=C>YrydpJ??x/GeAϸXs͢@Dž@GEv؀A(= n-$zu:hX]ÏбO`B nGg`wn*8x>@p>и{`rfp~>H $I晄!9HW>@!dlGwWo$*#׃It#EAW<%P 󅽃Oڪk'm)HRFR> RY8Trs endstream endobj 3901 0 obj << /Length 2337 /Filter /FlateDecode >> stream xn6=_YN{Yv@ =x%bіE6AчsnFY4{}%dz ՗" qj9Wo/Y8fDZu𥳨ڷ~YѯYg(B %dF%9yHouȉ2$.ȅy oP?'Y>M.>jh`pj%yN<.FX 8R%_2ٯɏzd 8 x'I 8 x 'jYP~OVS%Ј;E ^7T AMP!Č$<#@nL7F+Υhyղs _/)`1D |7;-TA|YLDH8-R105= i4[1#JnK;D#b5"Cܳ bja¶ n%&NAQ; `HeGOx4 E+)FQ UB#*FUPy:tWiM+ F #Y%nſu6XSbvF8>gMCI&.}ͼY}Frn\m<~ք!>}c rdtK脤RnUۘzJ*po*྅(8bm"1SW&dJC^ڋG"&""XH% 'x|HwNy*b'Cx'Ĕ(@EfYoҘS%m\GN:]ܭS֢ڸ0 anb=zE9-ukd>K%~_VZfOsEϾ} hSt h &b~Iyq$IG[e,{&N yfo[2YBf]ck⿓{ÚuNb,E^ZVYaR/s]gbcB=F>g*?I",}WlΥJ|p[=+cdZ{;-4&q5v9)tX?c#JzDWY=lO~ {zO\][\ߒd<Q۵hɐ'ђ9vaÞV *zmb 3T\LPgS(BX k!]%:/iPĆ"Hp^J>NfÁ3fUWn%sjVA! "3裎@M~B"NI`<>6>lg>(,mmuً؆k$"@qp#t٪1@T8>}IDH<7U̞Z6sJڵa|x=22./F ,^[h*Y.iyl•9/s5+1rD]m5uFPOQO}yvحEؗ]-| {;.c=ESȣe'{9JW*PqP9A4i\$jطM$To;'ٗ8=n5Y %B*w ˓"|'%xA}gUDN ]Kní扼bLiO9PNY?\q}L5oAy'`Bӫt\m&vD9ix;Ǩkjmjo]`.$_:-5TJ`VW7*f;#_X\i_=8X&!)um-յ碵H[ Q4_\֋=z`KWR.>Buj]xZsZupSSWOۨY3 6h/?ҟRWѕuB:h3w4ϭHe5H竫R͢ endstream endobj 3684 0 obj << /Type /ObjStm /N 100 /First 1014 /Length 2714 /Filter /FlateDecode >> stream xڽ[MoW1̛%@uH"D` }[K7< `MnMmoWwsRJݨA[sÍjV7,,S#=5$Hڮ "cVݪAn =o =<]A%K Ֆ$h-iК l퀇7jnPj  Y[xFï nc@ ƐخPD} h1!=zj;YM Y%3+Pe}쬴Z6d@պ!B[X:}p'r_u-shUj8\B5!۳-T'zrjz)\R;Jл; ݊G+$m`pn`;hXM}̇ [%4UA:JvZèQӆðXm(q*e|yI=m%0@{T@pvCwXzvlFc4=M匀ѴmC@ɢ}0Hnt(իӻzN?ܜ~|w>!3?rlܜ~ޗc7Ē\#*d<*6zN?ӟ݇_?677o ը$r(DQ7$ʈf$z_HjD984pH}ARYHkL'lĔ9,Vb؝EMG}/cHXi<|-$a=$ƈ$DC)fDKqt'HbX9Y$J@(iȹƞ˵:}&c\":k4 T$c'PZ3NAb (mNAbOS-/O=IL9tY%,1Pק>癓h{["'CvJfVf Z!P̳0 54z՞N12?`d2upp/r o0LIfZ٬$I$^i7ton{ xAP[OkLI|య9͟XzgoDm )< $TKE0cHõ2KWv_u;?MJԸɦ#Ykǔ&Y@OLSKTM5iP.*]ZsXq;$SI#a2|RrY` mG}bBm}ypػ9> stream xڽ˪e)4L&ڪR! d{d`;Mnc:}Һlhoh[uUtmڼ% Kj4<ծI9- IZWr-K-Od]]Z):HТWpbޮhIb%aEA㾖|܇/4ނO(ңAj+[h"-\Ph H\ }}- Ѹϒ=IzⳤI f4j"̒L5p[Rٞ:̞t>%iWFʩxԪwTJ|GԚ}mmT:g{U@`c&5-h 6!DKN%Œs f3}pqU)g,vU߁0uRGpSik%%wƭ_L!~K›v"x/C0Q (C2Fh7;( ͑,D]^E7fCW zcLl D:.T Kۇo~S}oo?}_~X 執vG#d g2B=#q׷Çt>/]/?S&c7Yz#GND$킡'0x}=|f1 W4WyBz&PF /Bk9Dq9QZ~+"7z(\CpY B!31j}CBd`@0ePCq[h̓X A,AR\C(-Pt% ~vmkz.r!;,#c,/cb%1jT)YQ1܂P嚂W  2@ErZ!ICP5a׏_J,08$S]Cz<vŜ2ԉ]1Odfɔ;ę38 Hs2вRP} ,uan`]qɢ@\ҸDL`ziP$/T=0, (1a~KJLLφ]ihBm&Vms)TFYVPהUa(0_1 dX#? [~bFz AuqBB'>pL!'>pL!e X2 s9VaOkSjY{K\)ϯ&>=)j [?|9-L$Iq*ŜKIQ[<#8]g.)VN<鮆uџb)}B=}2=e^O]KWzmtWCW%EOb9=C]kط~G6*mLQn]3&,96bf'0c:aX9-s4qS4˪7#}7#OR|1}mF̱ωChr4/W+!(!bKg;ĮSy%aXCUIo<@}8D'ebA׏^S3ѱ-Ef+7]1#޲s@@<;c먾 &(NKoYR7IPov hQk0ȮqF6=E^q(18y(bD!5Ĩ'(A U9T9yW< zY.T C9SLxJ(F(:inu9"#scx@!0B\f-t#H)]؊8z@`x+7]$VAK3@Xt̬쁨\Y 䡠?!brʱE gH0SDPW\ Y?IN) BSF c 6XR qBZ}(GxpXCH t$3 ;fK%.ǩU8J>RmVP3[ Ѵ;dpOg8[R@vH>b * endstream endobj 3904 0 obj << /Type /ObjStm /N 100 /First 1014 /Length 2040 /Filter /FlateDecode >> stream xڽM$7+t\_TP`{aڷa13{/[*RW*SOJ-uMC (7jҼт$=.Y ToP}ec9P*G' D^R<2yR;U6oYVЯpZys!o*-m] G o`{1-7*~) £F޹0 i%A5-LS6' Oħ -bO4W%(a V1*Th՜ZsR,@!~r%cdJ=P켷鳅J&)|0 V\\8T=P+ȑ` Q_ ף_ x_  MB;B;C;pŨBcD|f|19V}Z0GÈ)U@\.\(8CqoRT0NC&$8ɛaw<2Lz*rp/g8DUUW,Fz@JL9;Yh\1k`k`C8 q;;`-S/޽~Ǐ>ܾO/?ˇ?'Xۿo޾yO/|sx G,1T("]}nçpg?!B$_~  PNWcsDS탐Bȧq=j JظȰC<ԝ!5lDPKhm#TXCc n!&~MAukEa8E-WY+%$hi-OEjQk#q&*lwd'h(m0|@Hd@0U&kS" Qc@l s&rQ+ZANc0V d@SAaL@9R~`&mv$~UQ}0}d.87Z5JdjEٹ"9V)r *łB >EfXj.=PiEU(&B( ń8#%ńŚbk1ԃo#X]d*F3)zE~Aʡav+?n-[$/]p*1tLΙ` ;9c5Bd6dk>L`11PT[c L}#XAd{BL1 ?> ;mfH dxB@qp DjJ0E##YAԺ?T (v[5!z?u,)H'b؉5Do(&H>,ˈRI2+\zqBt\C<8!׋ADAbkу |op ӁnF,r!|@hw7ZW7frM"80X Wt?(ZS'AkxkYq&E[+=V)vZF :2ܻDKWH Ƒ"0Ȑ1 BP=#]"'8ҁ0Ñ+;ÑHG!#]Aq4'F<E[7)zoMN c)fynؤ蕫(֗K9m54 'ŻVa3SʱD1wQ٩W@ҘH*!<q<rup^F\+daٞQ0Z1亽\4zi{5Êaɞ=zbhu=zj`OVMG,Usk1vʗ;3G%c)d!Uxp?ܢzm٩ 0S`1Lrѹn7fJ5]O"9# Cih7 ;]"R~3ێt;A1bMbo*~%#,S0#T@'p+9<tQ~:! ]ATC'D^Cз ;EB "FU\2Amh6Jsk*B'l BO Vjm3cEGbN ԎD[ۂrcy$Lvj͚򝂄N[7 endstream endobj 4076 0 obj << /Length 2178 /Filter /FlateDecode >> stream xKo6_c ,)]5ŀlV~5~-٢BQD)' |89 $ v  gPL瓛W9/?Jhŧw;97焔/L?Lx{$=TYdlr3 (|E"| !1Fg  /HxO Ð_$I.L\e,!4`tx АA4DL#$9p}  "# ~7N lT 8\0|)yIi{}NWQz'R.Ȯ[B\IlxtzC.DG3% 5vը0-%`{I* &ZHEqHVHKrR(\RoBPW4F^vPrL.7h-ؖ"Or-VUݬ}ر㲤~K* oYU RW:7Π/RXuTtV\G`)\"t "+2zKQٟ^gsF0͇ T";n.`_Sgpvb3٨R$-pM-]0dwp)82LMshTw 40p}=l׵І:@]FyKָvcz)0{cIMDmpKopC@iJv |<5 8KY(ݲ.*\T e/Zcv/i{D3fqG?zU4V\ p9ݑ 2s&n`T )QRa7+֔DmaK ZC Myumhexo0CԻuC0P7fN;L 8k{@h5'6^i2eV/ȃsa.}ϱ=+Xqu" mx o5|{MOj6?h1NRs5nV~g߮m4~A36x*f-Z { iAJE a݌5dVU\@XP;ݑKóPE6zTVCH&ńߗ9qx1|TU|0@o=h^7 {p m_Asr+i\΂/Gث3cx(7u|ɅwOlDO=par0Ov@]4խFӮ0@ka{;>O4x =1d dq[Rx^̻Zoi V2-qUW5z`#2 @!JO=;[ *czA]k8Wl̰ LN5__ eyH;Ĺ^FEzg ǰy(rש~< O8U}UIe:B-鉺# anN~ 4f b~T)𕫁>Rc 9 .3w|i;t%wde2Nf>?S|6_([5AyȁB.Bmg# endstream endobj 3905 0 obj << /Type /ObjStm /N 100 /First 1024 /Length 2824 /Filter /FlateDecode >> stream xڽ[M1>Iۂ :$1tpE` 8>zzu $rg_.lJ-һA+^db׌Z)TX\k P5>02@2gW PAʅl`Z6ѭgq.1?FK2FA2ZAT%F1V ȯZ@^4aԊà^!$G\ǵJ13#^ņ[ E`řC.r2pz/4m¥՘jV[+MzivMb Hp["m؜ICx;9 B s{2$Q?VsP ا؅%pr%кqD[6b׹"f%!lG(4#9;,%hj,P&XR!\ oe[vu3vcVEaČ2XE+g&0I*DM%e:l@z/GFt}џfSYl bsIM9VȖԠքYd3I`Bb >CT&] $8%15~@f7ͫEG}Jg&ܗLB?CmfsBeўIfK;'13Ё$Z]Z l>M&[iᲭߧ]QY>NAE;uOQC|vS .h]ܠ)t=[u[* C^*G:}ˎܒ;mDBآ)[Dht (L[MVLG8%13xqWL,]Lo~'MlzIĉ&# 'M)ZŸhIB9shU?) QCZ7>F)Xn8CN$ßm~v߉v3lOL ֐6uPco(5MPQf_7A(.H^AӑQ}1VvbE쪠|Yn4gC,.WlzowR iAia(-x>h$nqD\u}pge2^8%13$}jb}&*9s3 wQj R1QoBqJnzߩ_ɝ!nZaJQT ⠤f0 [duWYQ\ qW endstream endobj 4212 0 obj << /Length 2221 /Filter /FlateDecode >> stream x\[o6~ˀYN{uдE aPm&[$˿eK(SQ yȇ\`|+'HM8 hr=|x~럞bՇdKI= ^RyzZ>>EEajswNG=h]ӕn⹍ A)B@bW) gHYfaLjBA'R\.|;8GΗ+=*0NKbkջ_SM;Sfz–*ܨ{6 mnhnH聙%xY $A] >R.;N~"z@$_ Db=Y/30Qi6]cEnnlGԜR{7߉ZN;3UR 6D]{|GbMHEiW=$ӎEhݟp. zV;)? ?6 zV6d&/4Bz OV@3{(-s^GݹbsΒx9OϮ6a qtebQ_ë= qMUq}EJֶb ಅ_JtEMv&O+<PAK_CX_ lU*h66 7ájDm\JMxHR=އ…:Q% stFW!? z&Q%Cyb̆igWDq>'f`3o:2v\q0>_}q:1=#Kїk{@NzY+hKb%FO6DȥjQvJ)TK*md|W &^V0s.ˡf܎#i [T. ) Cs PzqG(]%EцܶZ̈́Q]yzwlp-owD˗Wcb{; g^>&8 }ëcm(,.MTKon(( $jV 9@WÇg.۟߼/E,r,  H[ @ȼk_H,(r`L7`ǝSdt$wVk͹59XL̏%yd ױ>SNǒW>QёQJ3`<빲٨9vNJ DP>>zK,S\ + tryLd5DMհ&XKq~b9BSjÆ6{B`p:fO/>h=7$eF!_4#BlWnvOv M!mfYXh\9u;HѹFțؑ:rG:~|zqDH;lR?X;JeiwIjX<^|k߄8;Me~x&PmpSiJWЍ!"'/r92Ec?PU N7[mbrxH}9Hx_89@Ƣ Mȯub'O$utb k@bVċpcc`V.Oɣi^4.m{KV El{b nQ*9czCRW&Z~Ap W5kř endstream endobj 4078 0 obj << /Type /ObjStm /N 100 /First 1014 /Length 2546 /Filter /FlateDecode >> stream xڽM+xL.V`$@Iy1v i8>oz䃇 3?8;췟&UlNr)P֠X?o 54^QB(q} D]$%KI֢@ A8PeVԴYKZx+Yj \Z`eCVMRڬ :Y?uRhVB۷xپjk*34܃lQ11>3C 7{6UХj|dM 1a8UT)c0=Llϑ%h߾P((][C۷--KvIbBiXC5 rT9DB1[{$%Ts)5J:,c\)4U ǵ946*[ eLwkCYki SIF]ln1XK7co۷`6[0_؍aٳ(fyt֔NO5hY5þPsꦀ&f yA #9]V04ua/L[l>4xae뀧:xaӔ܆4@>C㿒Dž9߽xqwz_ۇǧӛ/zN=~ӻȐޟ|w4>ܝ~މPi) D4ǼxEE8 ?=} |}Tc;CQͥEŒ*X#~:9Vd6Dׅ"&6< BMr ꀠ@d̽s/Q-(# uI sc Del$y}@$SKo0 2btlH)9(F6-_d|(b`F\Wg9 DBsYi<VoLJ9 j EIXª}b$FEJs$= !Ff  g@n ,QHp=fO!ڥq b]ʴX2rKg lFjg%3̲pGYp-By]Wfk(qT-s*FULveR/@Le9UD!3x1\9([!,uPQbA=J8T1KS}Is@mpNu}BHI`D_ (Kʊu!˃a/ K#՞_{~9Sj/=B>< r A/9]!JQ5ΑhQ`&K Asj!bO+w'<: Ff5EhWxs _!: j@K7ؓ9_h R::!-{Dq<lj9w Jc D;+%G2}'QN[d҅fmiܶLN ΰM ώ=x!V;ZsV×~_=>< WW9ڊSH^zpz{Sxx ƻg;ov=/>ޏo=HiW$l|Dl`U'WFM o77s;7ܼso777rwݕ+wW]rw+SJ o77 W&W&W&W&W&W&W&W&W&W&WfWfWfWfWfWfWfWfWfWfWή]9rvٕ+gWή]Y\Y\Y\Y\Y\Y\Y\Y\Y\Y\Y]Y]Y]Y]Y]Y]Y]Y]Y]Y]rqŕ+W.\\݊ܭ݊ܭ݊ܭruՕ+              >~uh)c^ jԡD-~0X8}4V).\a[#tӳSV # H''S֦ٖ? /7\1ʗIbgmFl+gsf^.oJ0= ea7qT8R^nT0(8m(ws {)oȔuUPq  zYډ#bQDf͖BGL#ae!`#bauΜcCs@~8XggdX3Fb #>TEX)$m endstream endobj 4215 0 obj << /Type /ObjStm /N 100 /First 1014 /Length 2339 /Filter /FlateDecode >> stream xڽ[=$W0Y$ 8m6Rvp Cp'q{{nݞuc"JTTxI_U^xru^4TKkj)oR+֌W븲T^y)ZsJj$&$JT$.s >$* UKZUOZǼ%UsQHڅK+S9`E`#>L|އ}̯aQ fr-ħ܌`XΑe~Ƒ%r~Sp5RvΆb6$yijQ8Y^mp[Ot7R6A8 5hL_C/ӰKg4:Xէ/kKesBPa)Os^,4`Ę1# AFt'j<ӕCutX0*89냊 .Abx{ދ`y/f{1făeT _&-~fa`6 MZ Tx~@CgfSy~n~|?v×_闏_oX狷?keoyZ[DTM>w/I?>e<7߼g Ŷ-m #\yt 27Y6G`Kf9!f0>iQ";^s:w ̄@bXCHL!׀ ?‡gE0PNT@Y]bd*ϕ<վ,C/#n#{ʃ5S]"XWZspyA̢> ىWH!3 &eDC"^$#DAvLiM,ʱ;=h;Q/5$ +C@E$9"f!J d(!2>dUU. F67T[FIH5[,hK- m/,l6_Ra@l@ɒ c=[?"tFgFFH\K ht;ae74DE*8vD H-NA%`<Cܥce%@ô=R;TPR^QXDAԮZ;^gJ; ,HmwN5?1 * QWB+ddS63eJ~Ec8CP,&{/H\~Bf:ti"w~!J]8aOWȀ+Elx()`v@k[6 u"/1Ae:vp9lA<(gre3#Dp+)ezm?Q1FQ~r}:xO۵; ژ:e-;/$\كt.1[[0d[ܹ&䷸.!jnz W([d4+ HLq 2n(Kdc%]zj>23d\9}\w7 UM VEQ`Bv,PӞeAk5i,~ML -.*ggV P V-,@4V66op }x SEHRX#> stream x[[oF~ϯV*_KJۭ64*;30Cj d˜9߹F_|7r)8S HphݾB~ˡ>J$)MhOo~/V^`r<8z-C|낾2Zl?~Xs"J{ 3xl>AT^hE Q}b#jQ#LAg,^.-d Yd95YLfP#&|[TC STb0xHlbEW%F'}i|%$WfC]bnBP p!hϸ>p}ZYLy{;%Q*Ͳgi].6|")vH"u_jX3TlNr* 88 !Cs!jmL )=BPva7Ăp3`Lʀiǀ~,X"1@Zdh bދ3bQz :S /f;gb ŬZ$y-À^׆- H)}]ʝK 3$OӇew'|A㠗dm܍9$ B3ԮW|<}B]ǻS4n;w/CLY"Ґ!Tؒj(n !9tC>mTxR6F~2@)șJ@'X_n|VC鏘 ;CӡB"+U2OX&e,$)'/7yk0ШKdxk],f:eI'S3&U x)U;CޤjlBh$; pĂ7DTIznHPTu@ u-H|gyڈ|7˒*K ڹedBA{G[muk(dIABY% t-|" 0> stream xڽO)xL.mAI,:("0b p}^zs h9=fWٽBB B=b\5$pWkhܬQB)*C9=PRS ;w-@yfj:+Z5dG 3fp30YSrXZ.USQ5J:EE45hWl#?Msub s/sŅ^%8N+䪤3{]#'hj4&s2&zWXms <$̱eCsvic يgRPT(ڶkfA QTyFks nPŹShLlTV+EW[M( ǛCzǛ2]o`=b|xkW; 4C^KW{lO#hӌ]x(n<=AbJt!)|S4pVփ7k _id*7Z 7d W;?xB,]r9&`` .UIgDҕHK sM9ڳݣtf7^^X^)+â~4^}ߥ m^;7ٿ]im]{wߝBԾߝBߝB\h˹<ނ܊lay/^49}R Rad<(My¯y=WL|bKm6 kg&Qk+n%!$Bz 7>!dv7Sv}@{! )C>v=X ";lsGXn; ;e}dT-,j?RE*U| endstream endobj 4339 0 obj << /Length 113 /Filter /FlateDecode >> stream x332V0PP06S02U01SH1*24 (Bes< ͸=\ %E\N \. ц \.  33qzrrJi` endstream endobj 4343 0 obj << /Length 122 /Filter /FlateDecode >> stream x-ɱA($ \vTSHB $:@\#Q_TQUE&MG-nu8M [Yð,ΐV]'v=WN;S3uz3x:cE_ endstream endobj 4335 0 obj << /Type /ObjStm /N 100 /First 985 /Length 1896 /Filter /FlateDecode >> stream xY[o$~_ËU嫴BbYA Į%C 2(ߟsgfYA'Jz|+uqڒ .jNH.\bs&!قfBœHE' T"Keǹ8ITuRIXĩN5GRXN $;-4\ܜCC.@)ugSsVX4:`5rQJ'jD(j` SΙV+D]RkZ*:WZeP+9f̑JAY`K)JB*ʽ@^HDz_sHB],l-@F!?9QR!rH#>DAq*h)P+B?Kr?B!c#yҹ!7Sc#*ʺ ] :0 G1`E(95֠Ot )]M9vsC$<5U"O3LE(. T(RR0J5vέ WOvjzm/zsjz{ Xjjbr. TILd"~'OMo^l>Ah.TK #B3v"uAb>Tb@S كP9Be9+|/=7C|JaAMkZk&r#h4%= ´g^WU:fz;_D9΂X+,Ƚ<5c QJGhTڷL5ژ][pF=/9B<#}N|C>4])g# 'PE *X(BI.- v,e <+́1@ s0(fs`F#]!?2pNC.dǐPwd;@h@<ͷ[M][wUQe^e;MIW8~xYҟ,uͧumh&k|~N 7bk'寷O3uOEs{*f&13xX0oWTe|:>~gKWww\hޏ)7=sl|A|sv^S_vy#I8*0^mK9e x(Tӝ!A((;+qkgcSA~8twZ96xu}G?{`<ɑYV U endstream endobj 4358 0 obj << /Length1 3011 /Length2 21311 /Length3 0 /Length 22805 /Filter /FlateDecode >> 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 4360 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 4362 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 4364 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 4368 0 obj << /Length1 1626 /Length2 14352 /Length3 0 /Length 15203 /Filter /FlateDecode >> stream xڭctf&vضQmbU*m۶m'T\Sاϟ>ߏ5ƺ'9yϱ*Lޕ`eg`# osQP|s63vr3v5hbfVV +Z]E$L毧=׎ffWK3$ZRA ifoll Pr32Yٻ>LV7 hfj=;`ll+{S[7?ᯅ_`J..VY$.V@SJoZWc+{?L@+G[cst 7+{B@p60vښ 7?:[Ǝ^v`bfk7VpL̊rԹ9A _@{[/IoJˌ}$7PB OK>gh 7[[cd @ϢqYz9ٿъ:S'j%"iafdE djj 07ۯfζVfyWK ,S2 /U$'),.EX2T;j^ROQQO7 '7 _X,ol [73˿#Qu5%Gm]Ufn}/:-3ݵ;wdJLw|$ԱQ ơ?/JPƦv3Ǐñ>,[|_2mN. &R?QWKr:{S*%P3l0WO4d䏎H~ ](M hug(OGG{o rba)H\M?!_ݹAudֿ1;2ͫi3骵kk5DKĔjO% Z A2H!_]!Ə渘9 eتڨ-OA!d=ƿ r$֛q( dFuเv8lQUsC-Թ3M+dzzgd4 < J/>f\+ /X#iN./CɆ5 FNֽEj0. (R7J 7q DeIZM.7 Zl+Os?6VehjZEj)c?d< ZrZW@f7b+~N3 aV cp0}Sezw LoV#8V<v\׼WP]0_P /RCHoI=?x5.vwJp}mDS'>'+vלK>`W%XѰPCM%mycjՄ]F}r%+*DibɆI#ff'r|`qaEG5mp[өKc7/CGU_YARl +_pz v Fw3_23}kמ=hae&J͝3 Qd-tq ǐK}ցm~yE IFS/TYgTϵUN҈w?ĬrQ`G}TL n~)htI}]/tv,}Je<&E-G[-˙^r5L* i,zR7He)вHgʟ_} 8.&o= e#^ R=[Z0䔜PB; weI24s[\J|:qc9KM"729Ej(؋%lw33re#//fۤsK 럃zuh7 e@LgT{vYP8U H~bKzQA9f|pN7ܱ.@hwz>e3d6EY_aFG~ͦͷ1UwF8]|c(I]N60^UCQ"6qbg>0 Xirsg1tЧe ?5CB!-_^@h/ >\LGGsr۴" V6B!5e;NC Tk@ `ǩ%>刍b9[Oʫ[ii % ퟹGDJLwRھ9]# 6{G"nu$ W`rL *3/ q:WKYգ$Ki}}?Xgh&@ϗ?["h!( ybˎPտ3#UbNhv^ H kV[ q4̏~}SAIH:Ӡ9jto*FuU LTU_qd-v xAZ~dIZDWFT( .6[z2m"VwNxjjg/w 'AP47!?ZZLlL-1<jf2X&-G'#'*~kxd=/R5^JmS~Җývë ^{SE^\W$c,%pdk َȆH2uAXT7XVju֟~IB1=1WKUWШ[&{D!=69w=w9 W>JQ̭ Gapxc'55Z& :A9, kv0+Z az:(fQlTb4kv8m'=~ q7Ri o`FӸ=uvcM1N59swxgkLץD=V[L[ DϾϝB$M9~F^9,nėAB$Pg9Ȁ>k)xoϩr^DJp?mfc'ArxD?rY[4ǚplij]]4ҡpuO)߉%9jB?2rT^׶!ʓ\W!oF|$$L8rmqdag.kiu oʼn7L4ZoEnR;pz\ض$qG,鎌|!#OalҴ;ϿmST'VnSpK7ءveآ:ƴra .NUV8\{fgtҝ_fƥ `̀v7dJb-E!UpPrMJ?e # ԁ5 kgmL^(kOYrWG 2T-~z$ꎭ P3S&C09÷F6RvzM^;ŝ)~Ն?{Q#'.Fo؆!a_HW.AhN9ZKrR-t"VpR X{/iߓMt<>)x"j\qI2I裇yw&^%ȩv@q~Qt*1y SVVzʔC)+'gV&s%$pv%4**2kShy7& ۏ|҇[Fl}3!ǰWt P3rji;gi],WJwS30쾹R*wHJbHKâ]R CaP;V0~ty,tYT+ncZ['| C;REno.Jf7yh W T?f^{?+}t@S1C̀Q=2m0"j*p(=A6lEjq%s.s9?+o4;&) v ØX+# hF i[ei -1jV]|?O\Њa8J@>>K~(>v{UptQ@%3.NHRg]((vx;,޽rNSQj]軒̩3xqg~ t;? sܰ(_PJ uV<rE} ;GUJݕ7")1"5.tHB s/UDrFP|XxCoMcdy',0L3Z^?JJRiL- 52p1p0^amV8tiFEceNc؆&̂5/XRw22iad ̲ f-. ƷD~m"v̨Wʾ%ZgѲ+AԻv;N-a='P(לϷ/c&A@>Cu䬳]ضR٦r1(5q}͙?OH1k38i&q@!\(Y-lό8'gFd)輲NH@bN=<3X/`,uU!l:zM'Y.~D`tlS+.xt< Ϻlag( 0gBH7tv1Rݑq87ZZ篡45T֊KO 55ݼpf:>byU39LU_qGPp0 hA[f2p uxQ\2sgDS#ntl%h6G6{V^,\$x&@[rT>PC_#(p%'H /G7~h5NVr,y"y\B ab$#LNɎ0ɶO;&#wYu !j- ޷Hd"5_8aNڢ'5zHh>vQr1|彰L- Rqph0_o Q&v[ȅE9/0hEz@V>4hdh k^CLY{4qM2ܠ'Le ^!ة [8H !\Ɏ 2E2|v,"A]ڽAo"w)/H1 ?ȞCڱS瑳' =S8`ՌD!>Fp^bFӫ6Qa;םcU䮡DưAXGwt${[a10$ L L4:TT0& oww׶pk` kF3+%hYrf7(Bw8V{d9iƃ8sUA1gBrPȕ]粪C@-p`I'n=Gӊ;Zқ[ɇux*\ckazGys45Lk *6":fU׿!#v.7Q8WRp`j0BŵF̄(RLn/qU'puŔuo=4{yT9𣏕?طfڗWʩ';yovŧdP]\Zm>/tiTȟ2,IR;mJxKһ ~n K[PmxX--r Oa`ǪZgsa{q^frrg;%g23)gPa@a _3_WJ(:%p,'.s荰#slBNpB|h i(W"ZSdLvKQ-PH]~l2޶3iCPaYJ{;慜Nq.zyCݹi5vg_rAR!$ǂD $Dy}7ի5ZimTɋ[vL\+ pH=Kk7v iv6=D^& S_p]i]Gu~2BT͜+[쮰Nńz9C\G:fwř9GW#0\ĆZI8>uK"8B]2?aE!@}BAFyo E/k">|PpI+/e57{ƪ':bjW݌Ϲ$fA2tTMݖ-s#塉o1*UjV'{ < tDž(|LE=L+Bg a{Œa@)t)j5c#ޖh"jy8t._~8'-7QrT鄗sorj5kОL<^* ap j{ N;r狀d 8<*{nn^ކuUHav]*FKJ-n4œ,Yv5 8N YbƜZRREl<m\w{c'$\?噩I-|{*cJlRD.!<*CꄣPc7߸NQYǃ FzbYd078G-b俚PhNѸ[k) -~$ҿz { |J97M>W}9NLV"_#2}d i5 JAԱ d81B$\>&#;($PkAqAd((j %mMGNK_09a/4}HKYP 7sJǎ($~F~8jdq龵^.d9fk 5WS͏y..5ZbN*Wǻ2:CoA+֋C#yZ켅w `ʜˉ"F%ϻ4^9KAP#o y @tP򠨤 5&%!4hp?)ڀɣ{4.BH*M,bdx4s`dYt=1OoWRJ P9\>qxT5}ua1A Lg\7mSv(OJto >©6:ك;C02b4Mv;ËA[S3 ^_sX[DaH!#F6E!97JFRy\vPV2(d qIxS{̔a .)\w9یОN˳7uIO^Q'k2P3.u}yc3S] CNK &n! ]]/< Φ3rZy9hŊ<Æp h 4RUN皮3tc;״;e;W:78y8d}j`xë"MU _MܔPB~f1%ߢAh̑gP5dd4ms r1M7W&}'u[ )xryܻIؖJ8BC q?TfᏖt?(],UBxH7|vߟqɔFTث! WœN^yIz. -<44f8 8C`䰀y0´sfm\NV]x66j^YjzI.wՑEazV[?((w[5--&tqW!jB}%JLw4-eG_Vb$nSHxJӄ E+Zl_~X~?ڝ9Q/9|! ^@¯eꁴer5vp{S w7Җ$GL*Zks%\ =GAF5y+ A"՞A#:8!(qlnÛkݻn..|Ds)2/v]7*b$[5JyMAܮpʻ%v[9EMA*x\w6G{!;R R{+fFCX4*ȱ">%Ȧ3L1k$K_=wP)M1u#2Ųp{vlOJSK=\ )"{[{*5f.[wO,B~&K/4r*Wk_\ıZ7Q BTk`+;'ueu8L[K z3_mNUt3)y Uҩ>* O?pXPcudk<ᕐ4P*I.)68Cg}z}HuɄc(Gg5C ypnia/ר]&>h@&P'c-˂g98liQ~:e2C2F@S2UY_&ƠtgB &)`FLV+L ̏(#P{@=|ehm҆Iߛϡ-[x汯֪yyX}shs1+ [=㢹.TP6&x6-g?qKcTr*E{5*u|ɗz-2RSīߥSi7j&?nyPVuœH_d:SeV|:Cve62k*eJ_$~Vxl]w)$ķ|-#>'nTYy}8IcabIOpx,T'թ K%A_jۦ#Ɂd^JCyc>3 Z^ O*$ZBpvbɊaޔG@X8h5Qf2xf(k0Zpk"w&:?Qi*—#Q2XĖ&l ߮3"QJwmikX3]W\|al Hi~+O| ˁ{*^I-c؜޿0bbX>o?IZsˣ b²qrjum(2l8`]c4!;0A\ lNҼ}mGu5p~azt#ɓ}-Oۇk_>89Bq`PvW_9XWMDDZP;nh۹ t]WޙkL+97de\PۅXm)b_95bKTd4r"l\`ɼMCZ=>F?m[@f:$K2N|z$JUo@/-Y[' , ] aZkTUѫBQ9;=o);^6 wD$5Ĕ{S8 Å~CȳDDgv{>7|6C2]Ipo}iGс/0HHU5Zh[iƚ~sFhP=sԏJ/h'I֔ Bnr8VDc)OK&:5Y݃T!;,%"\=C4X@r~nKk:ߵlmM'*95g b¤2&AU#g50W*]NPv8;7 TAm􏍷 ,"¡\aI`n%^U?Ho;Vdyo{"B[.SԸЋj0kQ>uj%Ҿ& 9H(Ifz=<^B: bQ3GSWC}n?܇[Wbq^_.K.@Bv)X0!~ endstream endobj 4370 0 obj << /Length1 1630 /Length2 19330 /Length3 0 /Length 20175 /Filter /FlateDecode >> 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 4372 0 obj << /Length1 1644 /Length2 14541 /Length3 0 /Length 15402 /Filter /FlateDecode >> stream xڭSx]-vfTU f%36+m۶UmV̊7Fo~3ȔTELm6NL,E-< Ή@E%4rڈ9y@S8`Aڹ;̝4* e ? 3.@+[;k_kGU dYbߔe4R) ll2ȃL6@Z[տ[S?92q&n@7?` rt 9l1r6'J _2%[G'GoT%qdnOlG_`MS[J/dq8ݜe KfWΎ ʀ43r0::OwNRmu?s99~0!i7Ya `e?0ÿDM` h7$Ne9$DwG=wjIg++E#dl @Ϣ2r|AV'~[td2NF"bcWF&,<@ 7oeW1:XlWk,, S3X#!ddU!+]T5?nOFVF_x8? FN 7.  _~Y15gTlLMJu8n@%[@Ԍ4Zܜ q^Vȡ |jo5ALSmvt#8V=<"/ ھ|/%igW P:\,*o0SpW.Xv(&)1؝h`g_ \CgSz'%:wk0~qv\lѬFOPw |]r&dM`'1"d#zV/@:&6&kP׹$sµv^/țj BiQ97 +݅^*w?]zӺ7R&mAKnWw?F]8!m R9xh\o$wF݈c v䌞pD> !1`pKZ Q{Cf3j-z_Np k] XW  ׍6/Tvd,TaS"Y|tmL՞-ҳkHۘv\O5/41&LTRn%,sqqSzTSiF禍2/F .5 rs@{pq bWbS4iފ\j>UcBMU a Ls׼Zk.1V=_rذ;ڸp8v#Eob,ϕ X>w$l GOn [CnrVuhP{S d23 ؞Rnhlϯ\mlN^5?fibTEuA)if@L}E$7*vʤU&VV"RLA6cb0˖s"M/FK̋YF$8-a#;6ƩW|:$h >JL-'=UB7`wPaQUޏi)#̖}TLJ3֋%slrK4?a`lWTF-av<~(!϶z|j֫qH%˵yD8Дpu)`k棧RZ7k+̀$P֌_O-IC7gܞj`2Ey^%G`#OL=ߴ>lG +.#upe W" ܙHhZДLåuG0^|\(b6?쩙 an3=4tAaWSE@{%7e@T:1ԵO_+mImaBzMCl0?ɭ]F2٫V#hw~*,]!F eB9FCZܑx Ń']=^\dBҞ2ҝ` }Gv3iH\*.]ތt2C|EKBX^jp6dnJyx`ԑ5Ƚ'>aL~AH3Sb]}6ǶQO[&ۦN a]N])URlajN.Qի)^P:yC6ko\&y_.]8E'q  d0aIIS,RL?y!t X ۍSr?Uľ7y%TMCڂ?w_8nqOFK =ZJ!f2($xe̔΀#$'? PZ޶h[wL%KmP՚Qc^4ȟARh*6M2SRTPc%Ιھ!cVƶA^UveK0F1b晧OD4f<l ą]Qa+3!L9k!oj=  at9ra&)cS+K@3_e[KHvP,ET[ .@!^ 4Y1粍'IODoI|]j?c0vn+TAe@ow.N6f_C&+ePG{L2V?E|{/'? aľq~_b=-SRzup^&Fo[.;`avHf!Uz"J,EӢI}kpgo39Wpyҋ  k ӟ"eޤ~ pp3GKvx=Kf0 V) pd}KӋ3ip40 ӿmJLM 2s(3=@Fv9+K"QYIߠ"6k XyT'smOD]&BONWǎdJ-X(T#ښ?3W/  I|/V8܏"AF{ Ps&X*S~hv{OM(whD=>UB t  %8@fj6i# )36 ]zUVT쀻˨ݲ,˺.ȱS"猬S'V}|eҡ y Gj2砓V9 ^uk%Ѕ<i&ۦ׈f^hft Kg|9*wvڂ~ȸғ"#9mlAowD -VE#K.(ÑK*YF_]/rgLy?D~" !<;#qN+FUnXͲf:攛"ީރ􎟇 SE߭.SՐ/Y HZVm[-[6Nfhde_tFGsYeN+Wǖ+E7UҸrZ&&=BPn9OcO cetqe[-DV:5n hX1f٪gKͱ3%y-;䁉3^{(t%`<ʕKm<=aJ70 ( f?ZRC3uE {D> P `7ӓCqA` /ʓtYyC%`C-$MzH1Ig"_x ݫW&f P!_r#S&-{bj}n ^&~+c%p4A^HiXgM6z~v %m͊H|J͗ь%0Ƙnmn}\sMPSguM I)! /IM{*1Ō׮367{o2NFXmuZleJ2bh).H]DRg]xTzѽ (rl<8*Rn]ɌXIzr+o+%t DYc:JY>cD;&c# v0?7?D5+9Qld+ߚP-&$)̎_X ߳L2HR5171d1A9K.ՎT39Gz<ny2١4 1In>ZIPCE>:2YF!aiߠՀ],N[~u(koR \0O[sk#*J!ڜ'x09k;Qtj#%tYBi׾4YI%H6y͈W]Hg$Dgo|#V*v%0clO1Mٽ'h vzaDEe#_6zZ$u3A :ޗĤ-FLsM/ɔU^i*6QQŕ.Ua,e.E;23/B7R'l;*p+1A7$ %ל@|=sJ]:KbTØZ!<桿 ۜ(jro=Ѻإ8u1fꢵJ? x[ ?0T3 Œ^)"IaPn#vx AD9[ĩ8 QC;ߜM FHI>6-Q_o,9 '! P1aX>U .3߀F+[彻PL?z4 n'Pz.X ()Ӟ/|JWW(aR&F#D9u{_!+Ζαv26:٥34.ivŠ|ÕPo3/^,*3Y,rNQV /\hYDBo]iAY"7gыUzUN1y|մ1jWH/N߻ 23I4@仂:?#ґwGP LKY~]ܙ.H:U!^} m>yͪB̤;ǀ#767JGLrV>`9>fGʅj:A u#+݊s2G gtsq(]g&S.[k;$x[y*;Gt3,='XsHpf۝bx$N΢FXiYNMYĕCԕo"~*D ~LtYN`8a1J0!S@UJTI~^ G 2'o> BQiY4$u?U+ >d+l-߭\ʣ͸d͔BR9U6`g,rulvs6.PcKu0VUـU{Z+V+w ґLOᬢ]A[P4)u:f pToY$f7Uu R7$KeߋKyX0?tYKy95fT 3 ]3R1~v֢d崱* Z鹒4o3@K̷pt55Fcȯ&͍F,&P qZJZ+K oGcY 0=LT C=djzz4;H@l"7vFbiǁJ\8Az5+~c1F]E#Qa> %OkqᵋlcU%LQx~[(`~A/Vl mVghh&p\%d! /*W;•Pc/8 r 8f #>7]eKtTk@fҬ2cћL}‰G)V"DeDF7owF|{ !<ş4|,:|<>8' ]H7򳭶Ocq̆i:{>&"%.!>oLqs7d/^J1%SAvJ’"ZV")?2r ֌}g1ټ,ek2LPw˲%W/"K ?TfJlDB6~Hg 989ݰ}܉ن([ԡUt?XG;v>oo/VpN"1&!|IP5J]֪L8 2p`84Ty_Ѭd%ĬD wUKg<.z~2 %tj6F蘃6ml1^醐v[N'Ρᅡ%op tmLc %TqC+Fn˞?f#}sWdw!^ P?̙jzd{LJl9|ۭ|eb|'J_߉QTop,jP DRMOO[CvoR,2È Kڷ*wI chRm51(M7&p'؈.9P^Q|R ~Izoŭ_ťKFŒ&/ΰڽc.w\N48vhOtb_t]wFQx]#K\آB=k$"+3UGiȓ˗]ZhstX`]U< zЪN _0{r!b'v}';qL 8ʕRaq8Ha{)'6Qr,2ͨNߍhC9k}7 vf Hjk/ԇ1](:_a[cU]p~rlx,߰W i,yd˛($\m1t&tzs$H~#Eʹlj4\s.XSvkhR@8R/d:TwS5iҦI‘-ۇ޵2}%)#OK UO寬'Sv.VЈO@G9ܟuc5_ -X\ [3]P~.R,S[:n' [@£?3y|/gwo9Yo㝳}DZ UO9Ý4ެوۑ!9ZۮYEJ3s<.MˬytwO5=2w\Œū_mLuwX1PucR5]˓LS܂8(*u:kX;ΣN dK- Vhc,m“HC˪R3:uXh5ӯ):~j%:214W3B:ƴ8uN5hш`Ο~Qw栗߃]iخiՐ]iocQȕmyQ/,O-35O}c0ғY]_*KYP49]>Ô_9A0MG< U+NVs(ߏl6(iu4AXn#VVZG7J!@mį%5zH)dĸ;fCb?&KZ[xhCȽQNrkR*bXVT($Ȓ 1i-*_8Ff,քw#|st. Vm8,cn<ěM:M+0Oy}vtH_Kg֧)E-oABʧN8(1TCP[\+]Y yPW)e"x\Q1rj=e:$ Wwl+;P{0 &F9X gS_mW3p>/*gͼbM%TzJAXW#O{r` L$Dyz7(ƉTqTJ{(NwBuX[v3Ov. pZ7aEFk2w4 inSLz;O5|qz֊%ew!7ท:O`X+X%OdjbJK,y sXY ̒%);[* /+,s1 uCO;r3>+$J;8o;ފgB|ˮ3]J'$ ]EUĕٵnOoJ p'CѠJ#TwYvhLSxD;חzK~b$ը[l03)vz xqn[hA.T:dk" !Cd(mԟjjLXƷ2_ ,7 ˤfV?**{p\{֑C*7oc뙓#b)#"KݵALȣk؈@uAbrVgXGKfO݁L݉Sa]T۵Zo?ܸ- :SEQkiw yDQU7  b.<R[< LLpA8XY B{%ܵ = >9 R/kQI(T~H#Ԏ vM(VG@GU"ͭ9Gud ]V"DyZl5M8Sڢ@Or鯭xtxh{^kskyuΗ5`f_0Q~L=P~?tCww}yAC婻w^@'""`)p1:-ēCF7M)mfL`^!?@?xeވz(ŘΘ˜!98q,*8z)A/>Un; I)Yu4/Ue2i1ehFG.%in Wl=݇mE,i{o\?<.scfNs#xJxāE{WuWK0e"ݽ}S[0~vt0D P0s'O?QD ?)]H x`*ܿWVyA,jO@[ P/D`(Zs51#0 Գ"t Vaiǜ駃6wOД36g1E C1(bSIj)75-RnH? wY|/ Q%ܺ9w |Rgח_ï^Y >@qss)Nex lWs}!}^ Cԯ-Xymm1lUrfn哣Xo v>סXC3\$,dJ[/Դl=Ϳ?6/з@$_Fb5~Ԑoʽ_!m,s0|1cJU0#j:&i>#-lƧ(!U'u!ϯO N9"ZK wziBP+i>g.BY>iӓZSZUϨ~l̠-YՊ!Nզ *ׇcӝ 2|[ۭ+v g };=lwWw ժ"'KX]8>uؤwOφ-ҫY_#c{lD~~Vub,O,Bl.?VI.AȄ} ֯"th%R;yLaLl4e#eSFo?h7 JFV^+nc~AtcTQ9]IcKgVWIк &%O #$[9G>qkFNJuͤE雄W/E-"`cW0Y6`>ZbϏ|E"@]gq)(N9VsieǑ_">kM,6GK)*r=@\X>&1^C9Pqݚ\nb,R1 Wu,\X@-fD!| 5MzM_ߎazLQEˡYzьovN"..>bJ`ngP5qG1ߖdm  l8ϩ GG,#˻4Xhy't}5l4>=b\9JqhIDj!;&t>16ogv\Rqx|JʐU*ip菤P:;-_U|}!QVx=VcnHRT5`ytH%z*$kڢmPLIy-& W7"~w,¿Z<-uoe~gRfb3 2T ĠgB%!v'o/|c\Ȇy wum o.ch0aH L±<燴hSEu=VRϺgn:E_ sƹ;+ S_Uc $o{yIryN&}y4*0xqHj.4JS*0_aH[:lzp8FKKeq,XhlA`AxÔOU>..ܦD僷 X%qu qs`T-t~M:Uc"AS5Uҥ嬶Ed`ߨg/7PA]9c:)x/k= 2&b"RBYQɇC=mm[cAG]r" ₷\%af/ֆѷ\~PӺ>?J$2S# :~ Bh /XJP3CwJpDc(D%ȉ%as^ٵP/qj!i,,M ŶŪ?f+ %f.5 ˪s߳|Aׇ]{輡=emjVq^ah.r(FWmӹgP}+Xmc?OaymՊD*zǃ¾9ԙ6Y(&+ƚVC7N cx ܠc6GՌf9Acsjl]ȮKmmKW}:|P\<ݓѭn$SH7܇.Icj k)&F喤 –&7aKLiQJ'6}U59 \]y3n+ׇ9=@ǎ!l="%}" ~L$6d$ @ 0v6Os+ћ$-{vrUbpOc~e1tcyBah [j:OTI׫f&]C1[~C.Cͫ P/WUPwl7 9F9z?)tTdm@lkG泯O/Zt Ft_LozQ@;h5OjsO4RXxS 1koڗuVX` g?e~5D<[,' D$l Sh*m3[oȁ>e0E? dL Ogd@XڎcJU? j=ՖZId?JIK) ǂ))O0s X(k d7m,@$v'W0w+Xh\RDd$O[=4X"]> 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 4376 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 4377 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 4378 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 4379 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 4383 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 4384 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 4385 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 4355 0 obj << /Type /ObjStm /N 100 /First 990 /Length 3493 /Filter /FlateDecode >> stream x[Ys7~篘Jiq5TdLJ3R+ڢ E<'~1̀G}rQWle|%*$74ʨJJHҕ$[I5I^xfKhC{ZUZ6l5 Y%IJ;'QSYô(-Gh%*(XAcpřr꼮D?+/\eEZ S(#y̋(9pAN`qS9ʅPhia*) ޳r|"ArKّhsJ蕴! CzB7!^[XA I^!#W.h,)FgA$ Кkz(D@d+0@3# 4QFZ(qCqXZ !5@HPm\-h meYe+4h4b @!ap" te<a* )"P0@c \j\ T@B(riڠȥ3 h4U \!#ȕh"WEV3P ((Hd"TpEdV".p%\U±4?G̺偰B@4cђvA?K ݡ1|?z 4U׶?hgh!oHhl:҇-d%>,E>i%g.LSNBȯ S[A=ʶw򱟓_I'PIo D 9W 2 aIb"ݪK3m$DQȭɽH2\&˻0RJH;ӸX2}=!~h䘎X:((q:QH?u~g|u]zy\Q~9'o>:yợ|Oǫ_88/1 /43<~RGpyVV2\xh5NgӚ.OVÈA[}9^ԫo=`ُ{̞Ğ{^옝_د {ޱl29,WLkWbW씝t1>U#-ȁ ^(7|:ϫ1;g)&լO'if`z% Mٴ^.dV^,'36gsqͮNjz}]/(=z>zKU}~:m7܂-ٲl9//ي.uVٚg|Q/bՋO)`S8íJç''Ͼ{ő9 [?-4x׏qAEt XFJx '?|"c n#Q4N 㩱l'_}xc;y +Kx:~iocw:.7}{解߽\'v:` 3(d?pن(ӜR<ވՓ??z:_/Ɏs@4܀ +3~`Ld[cj7X`!զ^l7Ӧ&m E3&\uqvQnW|{ɓ@T()]RBH2 *ܢB![Et0#һp#=Gl&M߄v^4ǯ %up2V7mU IU2h'VE6>}{Y!]Gn#.63o|yqV\/ nJ}yYS7ݮ9UB-[Ԥ˱׈R~WOa7^1Ojt^VI R+mI; nCF/&FDB>P(MP!!!z\R 4'SqީF[ZbS.a!R! }%E귑3bx+{V/a{@&U Τ7@U9V9.h3طoS?n7XeU5=>]f3-{xXqYo'KJ568vlɇ8#n96>I}>mқNO)xhl5隓=uN7,\m8nm7]{,]r]:XllŰ˾ﲹbo8mܖ}[@R^ݡNn}zd~߰Vw~Nw;EĽ|M{^/f<#KT7ߦOe֪;㝌x(6ͯoow"xUpAxGG";NFrB2%AG!VЫw7EB5J(h*5}D' PI0(h.2e3SZ$5JDļifDӀ)cc-E`!]؆hωKX9r65=\Z3>e+hCD$rd QIn+)bHDIcDޭM̔GdS“2TʘR)qGS2&P*G!.a촹)c1<${ :݉=P~S&.'ib&$lJ)#DODSgg>-'/c^E<1>|ΪV#B*UBÔJTbGXQIس"ҋ1ͣM*F;M>;F]hjZq?xzU8]u{YʕaxigPdJi)x_QhSe`2ePP]a8 3ePP@uaTPjJ9 P%d@f@ 2d   Q@tax(;0<@|fXY%eS&H~n(k78)+v`X̔2)H~lB [vaL-. . [#a&aHJ$  0 CFP"aHI2 CG0L0H:aDБ0 0d$ %a!#a(0t$ $  C#a&aHJ$  0 CFP"aHI2 CG0L0H:aDБ0 0d$ %!Q.e"SV !q2_U=e%VIV2e :ebPY:de eU(t2)SeIV b3 endstream endobj 4392 0 obj << /Type /ObjStm /N 100 /First 863 /Length 1885 /Filter /FlateDecode >> stream xڍ[oF+X=={!7Z PKQP ߳ȣi8~K}4! iIcbCm@ܖ![O/+MCImH 5VnP[Zø4Sf^JCІCP32q02CDbfgP4158WL+ h,<ŵ1rSBNȖz[T0RZQ&35d†X6b{Lg2 >clSd7{)2 4M}C*6]2z}ԧo)"C #o7pJ8BLr,w̶sL.,N}8Y9W&gdN129&T @Pj(P,Ed@V  @d|I$ )@@H$,@  @X>D @h ,taIŠhe s;. ;$fT%,aKq _P%aKJ°$ 0| CI!/a( Ò0D% %aXH$ K ×0aI"a0, C$ _P%aKJ°$ 0| CI!/a( Ò0D% %aXH$ K ×0aI"a0, C$ _P%aKJ°$ 0| CI!A2̒0AvX\=,aPa KܰiZƩfA² V$ ~a'a`Ue#l` `T`TP}U-UT@U ( @P|E" +@dX>d @lH -I$d @@ ,QD@T` -A@P _QI0Γ#JQ(1/`hWWr7]Ѯo]%]˹\߸JoEml-׊j}*ZU+ kUUr7UѪoU%U˩TߨJOEML-J}*ZU* jSSr~Me=c;m] n=Fo:;LpyqW55v'o]\ve_W>?3o7ݻ5Sxø(fy6Wu[}q{ovzg|:}0%7˺3w/wՑ3;=Oպ?Ukƹ^3~70Kv9f~-!)/:JzuY3Wd,Tr]nկ}ݴŴ|7^{f;D y}֍m/K`@3?Bj1퇛 /m<ӑ5'`W7㮠Xc?k_[% endstream endobj 4399 0 obj << /Type /ObjStm /N 100 /First 1054 /Length 5673 /Filter /FlateDecode >> stream x]o7?즑[$koI %9ךiKfFJt?b?dg งbU*R( )˲pPqDDa`dxݓ*=U_(s^'SpŜXfV}b`BTN-/0UO^:R)W/ Y{ySu0S(Q9^J;ֈZ98/4z(P& U .*񪨤筋JWMQ'ʢfTĊZ~2!DQܓ, #BF+W SkWdcE貴9ǺG^0[sQ'UVayFJ,09T!mpZY2^3nk`TNm\+[*[&jpE1F!. ]m0it6ŅkekS['St֦K֦}i[(֦+P]*MjJHgv1%lmUmm5')i B[w2S:v^r*e ^T׀6y *贶.ƫyA΍vlr-jfviuն6kkֶ6d`Y YKhkSr]klm֓`lmZhkj36] 3ck=i`EJ*kg;^YWYOW7_ղ9<\.Vp^6HOͪ[v6~meSE8Q)r$۠_}R 9CtiR^Ќ_B$E섩g!)7c!s{-t}~1'/j+GP)iUx\6V92FCA"#Inud)A3.[N&vbw$,(]/ P5D}0ѧ|B ) "gi8$r&qv]"&rc 4M ?.peꌱ7m@j]pB vUq0VvW }X{4&ݑQ6 1q_!)X2- ,zU'ys&xiCw8)Oy.n3ϚPF}wجL{P /|2C&^:-:)ʀSF&=)&08'p`NœxhQiRtqmpbɑsPiG^zl%YT'hfJT oRvs n_썒iynG)qZmktCuhK4o%Qc204۬$ d 9*/PMq|`^Α(r%-Žӽ%},~>_m銶)H}s=u+;PYHEBR5QH8AAwR aXKyN$pɶ:'O)$ SènH7kWFl]-8gK\Y?HkQpNhA!xP&x|G$d8;Y1|ć1"c=^ 9ΘV&*$806K$>^j2x sؘ4)AkJWdgy+ IG^dܧ ʻ ^ĭr@V2!N)YzSO$iB>păLPuJF7bzP^hvvGa0>cy[u\E8 g TYV'1PQѡ)Y%m`L40Codž(CwpmE 42*: As(6'8BF6Gkv$1m297He dWuC: 7E^qM66Co8@|\y&r>IE~x6%<^Q`hZ, Q^gHzk@<2v _9ȋ~v|݄ZIm]ħqב,>}|2gNk'O H̅/10 vU/@*žtP>|GnOEý2KBx~eנ|ׇGbf]Kܽ0CP@_EX\ k[2#JuwěKD\ӆ[gpʉl؊3^*1Z~)9M&2+"IU o[D*ya3$;dx TEpb?~'ц!v<_mjdb&9 H xԊLd Ω_'g<8u}<~F&%KZyuyⅭ:酒)ӢhE5}0/2t08lt߾U$DZcW]rܩ):=y3rKJA('h%2toFsyEvw2.@[c1P!Cg I5pW/׽_X:<kOF#O]խw[)`ZI ߂IE{Jߏ2:qJ?mR+#v&~`Z{f5w3>.*sh"Os>8O4ڣ4<^q\O|P5O㊮o?cMSqq0,2xE#-{7Su xsv P"Ppb q_ O Bӑ2CLC%؜dF*Cn >TI !-tgw!pFp G ~Cٍ{> lJقHRnb2!cI*IL929!CSD,M2uj{z}+!I9X7Os-EbDX"Ae{$H<Ѵ?3(M%xapP)Q$MPZ.ª k\h>9-g5')}&}3۷_ M3"H}9 MhD;>nl]2}o~vzGF6?y{/ |Տ} ꃝ%L|-1֧e?eZbdBvZYQӓ˗?i(Q vv1mcݾې B.C"CoYGZ|Hڽj7LJH]4` y8+cJNɵ'5Θ u]>z\Qlls%/A!(I/ִuDsmE*3{5OJqH̱+lM+d 7T$%&w:+ HaC&Yڟ`\ݭWúYkI3ߤCVV.Jm7o@w( b9e TYP޷+j诅1]o\'~`֛o\^R5<9v3ޝ2y;+pЬw+^KZ! עNvhL{1>Y endstream endobj 4500 0 obj << /Type /ObjStm /N 100 /First 1036 /Length 4390 /Filter /FlateDecode >> stream x}\Mo] Wes|A. 4-.,TGMڎamKYO:ΦPΐp9}M?]ݚ'nZѶRJVC6b JղoR2&{n"%,'ZkۤX cG57-*ʈolȦuK7m:fS` W0͡Ϳ Tj@Cu@j[5s5n|ڷfZ376o}ט1֛@Y^b ~H}b h%s5(6S1;} 15GB9c>bB^!PNLn7>GLJRM OK9M"Njb /5_M*f^c龚*ùh|rW%NxjV# EDWΕ.ՆfGq;|5ajbxXQ)AǥZS ZȵҺ&<}^u 3YB3_mjCkw;@}|ݛora~Ƿ_p߽7o?nvˇ}!&lO~|[n|O|Onٻ'ːop/?ύxOol޼Eӗnn?~>8|?{P{o|{cgb_o?=}& beRw7>M]Jh{QnZ/HhP-j$*cI|X*eG䵆/;Sq z^Ipd3bD8$%g Q;QpƝ(Xש!I%j p` ˸pDxZ9t%j-|N_`8X^i$ fZ=(F1ti˰6\p̻DZvR$/nR򷎘 k ue'XC1(2B̐}ѳhv,D~00kǎ sߦqݭrAGhNk)"#~ !z|RZQ;;{ܯ}|b'#=IGHie.gY@'eJZ!'%##Iz:^r&3i<)sl<)厀'aLgg |j #>3D\DPJ3JyJPPJ%eW:}k<;H#@~=B<=[AQ!y r7T:βfӱrRυA AAe # 0<0<090h*c/*o/+3&#$0'<ѝr2"*tQ;* #ͫFB)tvE|  340Q`.!BP`;<]OjKV\)BWWW &_`@Ro6Fac@ ؍+3`u`u`u9g* W^AalRDvR6;⣂iw AY\^+3:01es3R˵JFטhs##07 yo7`{r,k?Xaހy'{`Nv`):04{xrїG漹;0.0b{|\e T"#0Ń ʛ;hXʛ;Y(?z.?Ʋ:W*o u =9o90$1-Bjc,ˏFys7xm]1G伇' l l k{QT}6vTؓp+H/L^<8%U1~e0;/J\G@Qlh!au e$r^6A( xb#"4[;< '.Af[F^6rKO t6 xbY`3XDW1 9Db!ľ8W`ae+t D+ Qz^B `Nǝ_v9)vbyׁ)ZF"0>Xy`vެ Lӕ)v*L~nͫVfs+'gW SgxzF`v<S! b'-`Lk3n^}0#&Lf-p͸`ؼ)n0'  rr8HQ|QlrOAWz9RC !prpz98s^N7}F Y"f.:$p@qt@1آQ]8r3RH\D4XBZᡩpuL+9Ѡ"nx*vY[`TĿZ44w#W~{#vڔ 2{Ci<n a;\|ؾ6nhl@yvp]}7P&@`ˆՁgSZ1kE!jSMdӹmbEmH[#-(OGb;T`y8'VJЖ IwQJՄcNYT dQ-n I[6$ Stz6N?[rŠT ڲ#i $?H&4E~h@uQ[Hڲ#i`:Y-N7z|;U¨tN=喤-[i1L~i !hrKҖ-IghDn D_ 0c4遞,vFIڲ'i .@'a F2h0-垤-{NTEQ4htbL@mΗlJq i\h!`Hh81rWҖ9 DMh#YcGhmrWҖ]I4 ƙDӨn`5#AE@嶤-ےi|`h`cVtc]U-i˶hV>@4+ZZh#1rIXȞibYT/i˾hSc{Ǎ@4Zrr*(cb[\[Kڲ/i`xyN <Ы +Hc0!U u٘xf:HOп`d5 sՌ1 endstream endobj 4695 0 obj << /Producer (pdfTeX-1.40.26) /Author(\376\377\000P\000a\000u\000l\000\040\000H\000o\000f\000f\000m\000a\000n\000;\000\040\000R\000a\000h\000u\000l\000\040\000S\000a\000t\000i\000j\000a\000;\000\040\000D\000a\000v\000i\000d\000\040\000C\000o\000l\000l\000i\000n\000s\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:20240507111017-04'00') /ModDate (D:20240507111017-04'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.141592653-2.6-1.40.26 (TeX Live 2024) kpathsea version 6.4.0) >> endobj 4601 0 obj << /Type /ObjStm /N 94 /First 968 /Length 3461 /Filter /FlateDecode >> stream xڥ[M W8À!!a8DdW+쌜߇[l rPvY=ysB:HSjEyF:Z :(SծSH.oSׇy g2 :iT[bzoHSL(Ohx,eJؽuJmJIFqRY| @KKBID|I ٽFK,RN$7,időP'[HizGS;h4~%DթQ62UŇL_jru朦ޛT#oMil2Uu):bl6:X[kC@ Pk,BS=$j,Bb+۪!*e`슣0ϖ~qV/,YӬT՜gVfuRf~ Ki%aDanQaf.[x7!5"BbMTqoR ꢈU]IJ"lDJ5(7P*bUI jɁu^I[l%%~B,1b@I]7a+9C,*RpxKś)$ɤ -O̚uHw={v}s_wrIs%&ӛ驽=Å+;,pnfGp77Pd&:;=f^X iF0l:V4əFav#hqhg7 PD#YHgW#HgH/.yHrn7 C#oHF+dt`^dWdAI%׏@{7Λn7W:8o.8o.ȫt_?2Jy ޹R^.9݁dB#oP 9s1,:y(B@C9ʱF8gq^Η[lc+q; hꢲF5Whsחuu/lckaCHO;E6b,6Yؼy]Nc{΂z6iv&k)vG6bwkgfMh˘N,h7`~wIF; u1lgo7Y78 Z` H/.H5%#%#%#{f"o0]BћtLH.3= PtaB[MՂbwM] k!v<=%OIb(勳0Hw `Tw ~eW{K!lgƹ_0lYgݱQ|sQhG6) *־Lni(vN;FPRm4SL>bvq|XyrWܱT4Xݥ:09$]O .Qy<uzFr[<+ѝUu9<ϟreNO:&d Ơ`^$~ ]?\^%k2D ;Gnׇӗ%WŪgƬA[7}5yoӻ -Ra2@Xɏv竧\8t"П]%nwow'@X#R;v7Ooݬ:i H/V aqw }T>M@6!%Ղgj)}*] tgW ?fw}3d ! !PNVkN]|ݿNj jݟ֗1n5)))~F\Z\oOՇnQ{H;bbb_RY-eǥJ- @* ZQ˷ox*쏐U7P x*VҙG߷{]t mx}}w|#!=]I+!*>7@]ZYexᏻ'gDG%2` L}@u(h@S.r 18z@ MCe *KP0mwB a%e,SDPTR~9 C덠NpR@+B IPN߼~  LfYeż.(-AiHEV!cYIԔD@=$!viYWT@1$!viܴ7@A J ].tA7 I yɣAd B3HQ.ܿi%]G{+ɂ2\2D!j䴕dA R!5}?]yPB2zH1D}y8hО3i Mq=jPDF6z5 )dH!/dCո=ԬIC ZP5.kku1TmUlKk)ď2~`?nZ | *sB ?|O_NϞ]Jvѳ~>>>ƒu^~pߎ{\.7~zq: endstream endobj 4696 0 obj << /Type /XRef /Index [0 4697] /Size 4697 /W [1 3 1] /Root 4694 0 R /Info 4695 0 R /ID [<845476D6834F813FE8F41AF82263002A> <845476D6834F813FE8F41AF82263002A>] /Length 11067 /Filter /FlateDecode >> stream xg_{ql6{lmy{]{wg{ z1$ P0zp8I(ɠ&$ `"H,!7f}|]9T*5LRTJ0N~TK FfԾQ{jj4Rjo5AVBk͕J+ՐS{R3k⽼\ ҩej5mj4au`k'[`Gǚ`VޠHsTۧPsV@sU>دvK8Nzh#jknkcj,q+j75OI4Oij74Yj5yOj4/tjы^JA$\Q;vU3PT׽A-/>zWcj5Tۢ/nU+ۍ/Z|5CCA|ԐTAM}>XMujщkξdr0&jkΩG::"vk://b>Ym;oU]Sg߮vV-wT۪/[Zl*^5>aF-F|9rj5=኏R{ޠ1Z||?vQm4͟Tj|u8Z-vk4x~Q~׮̟W[NSvU-y"4sYЭv篩Ŏ"PeVSgJ-bϏt/RM}Z|>_-v<5uj":cp9?U:/rZSg?ѭtj>Vmd!~ϿW+}?Aey}SϚj~3_FM=%Gj>hf`L{EXM24R5ɼ\#=);Bk͕J8Js5tK9Iѭ9FdA|ɯ0GO)H ECt/I* Ħ24qo/Ծ_!V*X 9X `=kFa lmvNa}ACpQ88'$p98"\0 W!:r8Wᥣp=࠷| 4.=x58}Ae6cF,.mp^8d:8&vHfqn܄[p]g_t&'SErP/'S +poXR5/ǎ7e`:r,:tp7< Occ=q|!;`s*K$uq+x oi}& 钷J^i^a|5*j F?1FyTӏjQM?G5fZB3Z\zяjqE?eQvwM̲ت aMk>BMkBXš&5[x)O}x!>cxO<UB$5[x|GAolʂTN' e,C0H媼V~z_u,ae +KXYV˩_؞Ŭ,fehe*UY 9|+XB˻_ qUXqUhBSД,/ey)KY^R(]>5LYYhBSr8LYy3+iR|Ĭ~r$e9/s^ &-~2er\E%QOzv2=K'=9A/A/@/@/@/eKROr=H/._ahڻήv#=edgѳSAOzqN+.{؊D' =aUϮ'= NGjH~~bSѓ@Oz_g-/20`1, t+a-JRQʣ<8lgJ/FG-KmvNa}PIjf<L!8 G(I/nnp8n_|nmv%OR3p Y8čI[W!nx6upsoŋgp9Iī72^/^_<'Y%gG~>O x ]slyWwQ$fG D6Ig4o$I7')/ QiJCTFHC@p[4!%|Rp? [A^Ґ4!% )i8IoF HC@4H5\[$AmچD48oLR{6$qĢp3! l5j<p>In􏆔4! i/i=%%WrD5&ñQ7z $7> L7 0Hm #&Xn M,7&?[al?;a=xUr56@PJ&6%p\/CpQ'.$Ybp9pMf\ W%L+6 n^NU8^܅#;O,s?;s:-{"Jrh"-ţ tcL'ށmʼnO0`a}$k~;@E*"PTD{y$`gUq^Y VXZajJ~+VZY$~;"\QpUD"R2QTD"Ğշ pD"@E*V$?E*PeJɡn|T@E*"PC_!rد_a~wEh*π QIr_ Bm%.5I]d+q8ƅFM9IN@!n]_]zunejGzn>I^x.)ݵIRѤKmWn@h.]B].]BzwWzw$<]~v{\:\k@Ԭ;wO&ퟏ%K|WݥKw7.b;ߵJI~n\˽$+y9@W"tEyn\>q;wS^&ݥKwt. 48:9`1,0~zyfI~4ٟ%~YgAϲ?,ݳt=+ g?K,ݳ1ٍIF$18\eNwW&_ "0+zPAJ#!@^f]eYg9|Yg'A^f񳱷 Ύ~g/īgo糜r>,QG|Yg鞥{Yg%yVf?@%tfFlOlڡGCK[K&/G!Cc]$+CB r9NC+qXcu.Q;Gs!S?gP;V{Es]Lϭw-h.2s\q9 s,137:_cb1sc9j#t9⢉̝hqƹu$I~k:s1f*H1b|x8r9.縜r9.縜r9榒ޏeu.r9s9B#t99scxڹ/μ7Iz k5$oCa H5x X `5I:/ka26f [aįyvn{a݆Y8 ę$\7NjPkpnؙׯwNI8|xSpns[;A {1h/F=c_y ܹ>&ILb{܍O`hx5nψ\Ns9rӆf$ߎBK~ԨfuiVY6T`ڕ5@t\EL:4=qiz陦gizfuz_ŅaZehz'L4 z> L3iB/z9i*/'KؔDL ô0L 4N14\N9uc$};=,aN`KjceA1?Im;}Ib$!o;E9Ո?^kԶ6m~mSf8Pۦö9jsaہ$/I^6ymn󅝆SpN@ylE= F0"M|~>"ЦMYh~"+ mahO-m9hoE-mh@6m uvἭOo&M|6[I[0-g!OI|lZ HCMZa [>xJ!!!Ժb(8: [N1eSFLQASөT6I߉wu181^48 <3u.e y:Iݱkpn{=u]a 1=Oc O2˾[!e&M.1j3|d HC`,%A X `5{:k`-ݰ>__b$& F `dACp>}A}='$pb$/EaYt|w1C:gPJ2{6Dwӏ1|)"[x|OW`mT2]et*ULW2]et*U;ly=y*UZV ؀T*%U)JI*ULW2]5`:vGb+LW2]et*o*U~V^]%z.\Ze5߂j5&5qY\V`.bQ}RR%Jh*UBV Z%Jh[*\Hx!Cr'd^~j;vPۡVgQyuB;vdV;vXaPۡCmj;vPۡwN$j;vPۡCmG:;$wH!CrNYo;$wH!vtݝFw;tw!C|;w!C|'cDO2M gI Yy~ bXKada9P VC:X`6& [`+lv. {`/pp1(q8'3py\IW%LM܅{pCx1) G |[$HC8oqy-[8oqy-[8oqyɭp>ګ|)x~-[ob~-[ob~-[ob~-[ob~-[ob~-[ob~-[ob~-[ob~-[o$ "X K`),,,VjAZXaFa lmvNa}ACpQ88'$p98"\0 W*:܀) 6܁px1< x 5 $-IzdݫHC`,%A X `5 k`-a#lͰ6;`'ݰ> L!8 G(pNi8g p.e+pPkpn܄[p]}9sy>}9sy>}9sy>}9sy>}9sy>}9sy>}9sy>}9s'Or>}$# Oe?&g~>}g~d?7cRLi,`RXYX+`%Ր<=6ց 3`6& [CgM;,igL mp˚qWk0tg3|ϸ>n3Ϙ9sL90s .3W"Cg "1|&1s 1f#x fϘ5cV3/%"<[x}왏 > b3_#gF|95rkb kș3_#gF|94r&h*$_xK$/'7Qs8r3əќ]97roLș34gŻ99r&rLU)9S:rtLșґ3#gJGΔ)9S:rtLșґ3#gJGJ+99r&rLșȑ3%0g9:ruLU䎜9;r&wLșܑ3#grG䎜9;r&wLșܑ3#grG䎜U_rtGY/grG䎜)9S:rtLșȁ9;r&wbB,,,Bۑ9X9X9X9X}!F b8_|8_|!n BD {mwM2{YxdE{Yx78B,>OZ - (:fRɢw<.RP${.dx4lz#W#~iZpqV˜I[dS"F[ >[! 9Y0` ,ZFYvKE|MU`rQrݾ`  V*[ hZW+6- ,X`AւE ; V,X`5I\p/&^\u#`Ƃu ?|a_XV|akW,Xd*d `E f;XdY(ZXa _W0Q`e ws2 7- #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.c0000644000176200001440000000024714616441764016456 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.cpp0000644000176200001440000000726314616441764017655 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.cpp0000644000176200001440000000357614616441764016460 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/0000755000176200001440000000000014616441763013061 5ustar liggesusersSeuratObject/R/centroids.R0000644000176200001440000003267214616441763015210 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.R0000644000176200001440000001157014616441763015201 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.R0000644000176200001440000022265714616441763014362 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} #' #' @usage x \%||\% y #' #' @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} #' #' @name set-if-null #' @rdname set-if-null #' #' @author For \code{\%||\%}: \pkg{rlang} developers #' #' @seealso \code{\link[rlang:op-null-default]{rlang::\%||\%}} #' #' @aliases %||% #' #' @concept utils #' #' @examples #' # Set if NULL #' 1 %||% 2 #' NULL %||% 2 #' NULL #' @importFrom rlang %||% #' @export #' #' @noRd #' 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))) } #' Empty Matrices #' #' Create empty 0x0 matrices of varying types #' #' @param repr Representation of empty matrix; choose from: #' \itemize{ #' \item \dQuote{\code{C}} for a #' \code{\link[Matrix:CsparseMatrix-class]{CsparseMatrix}} #' \item \dQuote{\code{T}} for a #' \code{\link[Matrix:TsparseMatrix-class]{TsparseMatrix}} #' \item \dQuote{\code{R}} for an #' \code{\link[Matrix:RsparseMatrix-class]{RsparseMatrix}} #' \item \dQuote{\code{e}} for an #' \code{\link[Matrix:unpackedMatrix-class]{unpackedMatrix}} #' \item \dQuote{\code{d}} for a dense S3 \code{\link[base]{matrix}} #' \item \dQuote{\code{spam}} for a \code{\link[spam]{spam}} matrix #' } #' @param type Type of resulting matrix to return, choose from: #' \itemize{ #' \item \dQuote{\code{d}} for numeric matrices #' \item \dQuote{\code{l}} for logical matrices #' \item \dQuote{\code{n}} for pattern matrices #' } #' Note, when \code{repr} is \dQuote{\code{spam}}, \code{type} must be #' \dQuote{\code{d}}; when \code{repr} is \dQuote{\code{d}}, setting \code{type} #' to \dQuote{\code{n}} returns a logical matrix #' #' @return A 0x0 matrix of the specified representation and type #' #' @export #' #' @concept utils #' #' @seealso \code{\link{IsMatrixEmpty}()} #' #' @examples #' EmptyMatrix() #' EmptyMatrix("spam") #' EmptyMatrix <- function(repr = 'C', type = 'd' ) { repr <- arg_match(arg = repr, values = c('C', 'T', 'R', 'e', 'd', 'spam')) type <- arg_match( arg = type, values = switch( EXPR = repr, spam = 'd', c('d', 'l', 'n') ) ) return(switch( EXPR = repr, spam = spam::spam(x = 0L, nrow = 0L, ncol = 0L), d = matrix( data = vector( mode = switch(EXPR = type, d = 'numeric', 'logical'), length = 0L ), nrow = 0L, ncol = 0L ), new(Class = paste0(type, 'g', repr, 'Matrix')) )) } #' 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)) #' 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( "'r' must be a single, finite number" = is_bare_numeric(x = r, n = 1L) && is.finite(x = r), "'xc' must be a single, finite number" = is_bare_numeric(x = xc, n = 1L) && is.finite(x = xc), "'yc' must be a single, finite number" = is_bare_numeric(x = yc, n = 1L) && is.finite(x = yc), "'t1' must be a single, finite number" = is_bare_numeric(x = t1, n = 1L) && is.finite(x = t1) ) 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 #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' @method t spam #' @export #' t.spam <- spam::t #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # 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.R0000644000176200001440000004143014616441763014043 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 Matrix t #' @export #' #' @noRd #' Matrix::t #' @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.R0000644000176200001440000007210414616441763014002 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, ...) { .Object <- callNextMethod(.Object, ...) .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.R0000644000176200001440000002502114616441763015701 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.R0000644000176200001440000012326114616441763015010 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 #' #' @seealso \code{\link{EmptyMatrix}()} #' #' @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 #' @param ... Arguments passed to other methods #' #' @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.R0000644000176200001440000000212614616441763014116 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.R0000644000176200001440000000763314616441763014512 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.R0000644000176200001440000000070214616441763015474 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.R0000644000176200001440000002175614616441763014635 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.R0000644000176200001440000002717614616441763014656 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.R0000644000176200001440000000352614616441763015324 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.R0000644000176200001440000002656214616441763015207 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.R0000644000176200001440000010375614616441763015014 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.R0000644000176200001440000054436414616441763014527 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 = 'SeuratObject') } 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 = .MetaKey, vapply( X = .FilterObjects( object = object, classes.keep = c('SpatialImage', 'KeyMixin') ), FUN = \(x) 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)) { cells.from.image <- cells[cells %in% Cells(x[[image]])] if (length(cells.from.image) == 0) { image.subset <- NULL } else { image.subset <- base::subset(x = x[[image]], cells = cells.from.image) } x[[image]] <- image.subset } 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, global = FALSE, 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.R0000644000176200001440000001203514616441763015002 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.R0000644000176200001440000001666614616441763014647 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.R0000644000176200001440000004254414616441763014474 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.R0000644000176200001440000001411714616441763014311 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.R0000644000176200001440000002075314616441763015050 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 <- \() '^[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 <- \(length = 7L, ...) 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 ... Ignored #' @param quiet Suppress warnings when updating characters to keys #' @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 <- \(object, ..., quiet = FALSE) withCallingHandlers( expr = UpdateKey(key = object), updatedKeyWarning = \(cnd) tryInvokeRestart(r = ifelse( test = isTRUE(x = quiet), yes = 'muffleWarning', no = RandomName() )) ) #' @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 <- \(object, ...) NULL #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Methods for R-defined generics #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Internal #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #' Check Usage of Existing Keys #' #' Check key usage against existing keys to ensure key uniqueness #' #' @param key Existing key to check usage of; if missing, creates a #' key from \code{name} #' @param existing A vector of existing keys to match against \code{key} #' @param name Name of object that \code{key} is used for; if provided and #' \code{existing} is named, the entry of \code{existing} for \code{name} is #' removed from the check #' #' @return A key guaranteed to be unique in the context of \code{existing} #' #' @keywords internal #' #' @noRd #' .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) } key <- Key(object = key, 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" ), class = 'existingKeyWarning' ) } return(key) } #' 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), '_') } warn( message = paste0( key.msg, ", setting key from ", key, " to ", new.key ), class = 'updatedKeyWarning' ) return(new.key) } .MetaKey <- Key(object = 'md', quiet = TRUE) #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # 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{nchar() == 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, paste("Keys must match the pattern", sQuote(x = .KeyPattern())) ) } } return(valid %||% TRUE) } ) SeuratObject/R/assay.R0000644000176200001440000015444514616441763014341 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) { warning( "Layer ", search, " isn't present in the assay ", deparse(expr = substitute(expr = object)), "; returning NULL", call. = FALSE, immediate. = TRUE ) 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.R0000644000176200001440000002423214616441763014506 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)) } ) #' @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) } ) #' @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) } ) #' @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) } ) #' @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.R0000644000176200001440000026173314616441763014425 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 } # Subset feature-level metadata mfeatures <- MatchCells( new = Features(x = x, layer = NA), orig = features, ordered = TRUE ) # 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)) } 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.md0000644000176200001440000001161114616441763013756 0ustar liggesusers# SeuratObject 5.0.2 ## Changes: - Properly re-export `%||%` from rlang (#178) - Class key-based warnings (#180) - Require R 4.1 (#180) - Fix errors in `UpdateSeuratObject` (@ddiez, #182) - Add `...` to call signature for `Radius` generic (#190) - Fix bug in `PolyVtx` (#194) - Fix bug in feature-level subsetting (#200) - Update `UpdateSeuratObject` to run without `Seurat` installed (#199) - Add warning in `Layers.Assay()` when the search returns no results (@maxim-h, #189) - Fix bug in `subset` to allow empty images to be dropped (#204) # 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/MD50000644000176200001440000003776714616700266013210 0ustar liggesusersbc9cc0a25bd146fcff9def80d708b01f *DESCRIPTION 93ee7b26ffb68997c62c3bb376bc8c08 *LICENSE e13626ac1be80078d62ff599a559cc3a *NAMESPACE 4c845f169983fb98ce3684ea286c9ca7 *NEWS.md 40147c0211c037dba2167a1c7866d4e8 *R/RcppExports.R 1ef5dee5fd47c7e5385f530dfec0bb5d *R/assay.R 680fba9a7d4fece4768a51a9b9ac90b3 *R/assay5.R e1ccf24f232da27e19d62eed57fde59b *R/centroids.R 1eb509567f14b62fa0370a45d8d92fa1 *R/command.R 28c519659a3831b5d60dad06fdc1206c *R/compliance.R 420caf5cb0ac2c2c33d66452e600577a *R/data.R 8528e287acd9a529cecea1e0b1c2ca53 *R/default.R 1dc753a27933fb4a91b01554ec73e7da *R/dimreduc.R ac3eb13a14fdd52a7c8a2b936beec0d1 *R/fov.R ab54540efbd19c4286332336c984f5d3 *R/generics.R 603797f73a6a069cc16224a8d8c6a996 *R/graph.R de3c9dc55d941f786bf17fcb864ef4d6 *R/jackstraw.R 563d2b07ff71614014300580428881ce *R/keymixin.R 542482fd37f94991c5e44aa721f928ac *R/layers.R 687dc6eba0dfec9b2d6910f142d15483 *R/logmap.R 92f0873f1b3d29a7857dd1e69675a4fd *R/molecules.R 18e3effc68b15795006aee658839bd15 *R/neighbor.R f69847f358fbab5c8c9fe2e7453d92e8 *R/segmentation.R 92dca04936bf1568f719691d509b2fa2 *R/seurat.R 7c2676669915ce229d521a00d38b5b1a *R/sparse.R 1eef48d6df27a44e36f07c9b41636878 *R/spatial.R d7ad997c3568597ce435194e7af8b20a *R/utils.R ac513d0105d388d9882f8bd654429723 *R/zzz.R a7ac30a584ee56fe762fafc1443bb8e3 *build/SeuratObject.pdf 6f283b1320cd5edf6e85a7af686f8e66 *build/partial.rdb 674c3364ad5d96d39b25c4cd5b40af1d *data/pbmc_small.rda 1949a13941dcbbaadc69d42f25221224 *man/AddMetaData-StdAssay.Rd b7c6a47d79fd5ad244af73162994f680 *man/AddMetaData.Rd 01710c51f1ac54f80d648243f607172c *man/Assay-class.Rd 3391bd158a40677f8b1fd4b0250cf1b5 *man/Assay-validity.Rd 4178ba0f97271f1045fb00f3a4703d40 *man/Assay5-class.Rd dc0fc9b0d2f57cf0582c5e1603bd12ca *man/Assay5-validity.Rd 886da2c0c1a5a8caf346e69c87740c6a *man/Assay5T-class.Rd 1555aaf62c4c4a887b673cf7576e6ece *man/AssayData-StdAssay.Rd a1a9ccc5cd8ab8b4ceb5890671a119bd *man/AssayData.Rd df2474a7e1a417b8cbab4c49485f4b14 *man/AttachDeps.Rd f90d45c55494c0be41421ab192c72af6 *man/Boundaries.Rd 69292b65557c90cd13dc0e2a800fb829 *man/CastAssay-StdAssay.Rd b60be7438040e255ae2988e0ebc3f2d9 *man/CastAssay.Rd e250f8f630be68518012988900f1f21d *man/Cells-StdAssay.Rd 1eb7ede70c63905e9da696ca9d4711ed *man/Cells.Rd 409ff54a695485b7c4695a5d66da9590 *man/CellsByIdentities.Rd d10fa9f377214aabe9d780858fb2aec7 *man/CellsByImage.Rd 2c579cad764df45ed72f767f00f27d44 *man/Centroids-class.Rd c87ae7a78e816a46016ec4d81b42d480 *man/Centroids-methods.Rd 9bfabfca7c08f1d078c11114decc8620 *man/CheckDots.Rd d635e9105f4d39a2fa198c5b27213a9f *man/CheckFeaturesNames.Rd f5993d80f5d703d6f60b8f6449acb087 *man/CheckGC.Rd 59da7d801c6985c9eccdfe699a88a3b6 *man/CheckLayersName.Rd 6d106aa4cb19c45c0e6a61d474bb038b *man/CheckMatrix.Rd c83a24585b63f65f1bfb903b3d40ed5d *man/ClassKey.Rd 069dd3eabba4634bd029d2b2cfb549e0 *man/Command.Rd a7fc7b318db8f99a3fb05d9f11cd27d9 *man/CreateAssay5Object.Rd 51f2518646e50e5d303acccae4a9fc3a *man/CreateAssayObject.Rd 20b26f942ae31f2075e5b76e59f0363e *man/CreateCentroids.Rd e9f78414a4a1c279bb87f1c1c9d3e5f6 *man/CreateDimReducObject.Rd 1b719d3bafe43063f6c014f5b7cba8d2 *man/CreateFOV.Rd 8ff669b5faf150077edab395881ba7c8 *man/CreateMolecules.Rd 1f994144e63d6f8ab6a12452742e7311 *man/CreateSegmentation.Rd c9b3cb218cf7fe74fc79e8fe9f0325e4 *man/CreateSeuratObject.Rd 74a155cf11014f5f5a9aba5a87c34b62 *man/Crop.Rd d7685f65cc5ea585f49f5b1f66e283df *man/DefaultAssay-StdAssay.Rd a1740a8c065cade1d35391849971de9e *man/DefaultAssay.Rd 99ce708fee711588494a9369c502b860 *man/DefaultDimReduc.Rd b40fa3f8ed226d67b8c92c91668cee9d *man/DefaultFOV.Rd 1e850302bd3d765b1aa211526112ff2e *man/DefaultLayer-StdAssay.Rd 1d4925a44a05ee751450878f93582fde *man/DefaultLayer.Rd b1ae75c119c61d3534cb7f2ace7958d1 *man/DimReduc-class.Rd 37535d2bebba4b6b6a5e0658c9cfa5e2 *man/DimReduc-validity.Rd 783bbd09ebdea2e2175f4b7964899cae *man/Distances.Rd a9f0c713d28929ef72aaa54af13cb764 *man/Embeddings.Rd 0a462cd54c3bf48c3471585ac88e8fbc *man/EmptyDF.Rd a868349a236eb9f0a358de75e13ddb44 *man/EmptyMatrix.Rd 32da5b514dcb96f9ee371fcd2c43c7f6 *man/ExtractField.Rd b9cc636b971be0e040c3e3356ed5d7bd *man/FOV-class.Rd 25a2fdd5c519b16a256b3233fd720491 *man/FOV-methods.Rd b96e612de1b357426752754afade9637 *man/FOV-validity.Rd 212bfd4f203aaac49c013606c011d357 *man/FetchData.Rd f1aa57c7b964b7e7e67878199535c622 *man/FilterObjects.Rd b17ef7c8fbb656084165241e777fd703 *man/GetImage.Rd f31a34a4044394e4e94581a846daff01 *man/GetTissueCoordinates.Rd 39cad81aefb0d22064d3c37e4f4f4159 *man/Graph-class.Rd 086c15f4b4f8e31be3fb415db2805776 *man/Idents.Rd bf14a7234369055870e88c662aa414b7 *man/Images.Rd 6f502c5667264a83b4a14b741db484b8 *man/Indices.Rd d62205575051fac061a87d3cf05853d7 *man/IsGlobal.Rd 402037af1d7eb91980d67fd36a2422cf *man/IsMatrixEmpty.Rd 9c91c183978b6155c0f5db4322092ee2 *man/IsNamedList.Rd a3b8f69889c97ba23ff3c43b60b903f3 *man/IsSparse.Rd c471c52ea8f2b8b6756be460101c9ab5 *man/JS.Rd 7ccf7fddf32bd17be50fb1517ffedf28 *man/JackStrawData-class.Rd 8dde6b2c1ade7e3475689cda367e59d0 *man/JackStrawData-methods.Rd 390424e6f1f1eb70dc70bf7b5f3574bb *man/Key-validity.Rd 77bf38830bba56e8ba84813d8f14c213 *man/Key.Rd 19d92b25fe754da151494e5aa6b79c09 *man/KeyMixin-class.Rd 88f11402733484e8d71c8656c72786ce *man/Layers-StdAssay.Rd ff37b34cd2ba6c18121248aaedf6a19f *man/Layers.Rd 441e4c0a2e3d197e728d52bdf09e4284 *man/Loadings.Rd 8e8fcaafa93627e072d5c0d77be57135 *man/LogMap-class.Rd 02943d8e3016c07173d3428d57bc40ca *man/LogMap-validity.Rd 7e93438ec399a4ffda4c53541e14f9f2 *man/LogSeuratCommand.Rd 2da5d79b677baa4e0300588656664100 *man/MatchCells.Rd b8a6d831bc4060ce034c7bb2fa933ef2 *man/Misc-StdAssay.Rd debbc045587f9edc282e49115480d6c3 *man/Misc.Rd 460e50a4464ef31c701115a8e63d85e7 *man/Molecules-class.Rd 027c61c6520e9b48325176f5bfc12924 *man/Molecules-methods.Rd 8d19200002e318007d9e63849e7e8a81 *man/NNIndex.Rd a211473cb0fb7dd0d75ed5a7747d6209 *man/Neighbor-class.Rd bc139f0d3945a84d8ddfbd13c7fb91b1 *man/Neighbor-methods.Rd 27975e7b628a5d5c0d2225698f696def *man/ObjectAccess.Rd 0231ccc99ad508f8534acde51b812efe *man/Overlay.Rd ea88bd712b28cbe012037da7334a6014 *man/PackageCheck.Rd 0763f4bc3cf8313d992509b76bf67452 *man/PolyVtx.Rd b6fae00c9a63048b5d0aedb46a5385ad *man/Project.Rd 490079665dd34dcf9df907dae7f9f87c *man/Radius.Rd ff00ba51a172085b0f6e3fbbd38bc191 *man/RandomName.Rd 7560cd845d076a824ad18b225665a8bf *man/RegisterSparseMatrix.Rd 1930b8d7ea0b2a339c8bede2827bc6af *man/RenameAssays.Rd 9edf0c4ab775cedcb5cfd2b46eefa883 *man/RenameCells-StdAssay.Rd bf223ac22cbfe9bef3741690fd381983 *man/RenameCells.Rd c87b87cbac30bd59e205081052a8a206 *man/RowMergeSparseMatrices.Rd ba0e5a668137fd5370d45643962e19f9 *man/SaveSeuratRds.Rd 5fef8883a18ca54ac753e1f88cb2d599 *man/Segmentation-class.Rd 8f041fc435b15fb99d2cf726215f978f *man/Segmentation-methods.Rd ea06b69a3b4d7eb1ece25cb752d4a22f *man/Seurat-class.Rd 946821f351dbecfe1e2125ecf03393a9 *man/Seurat-validity.Rd 3564d448ed3b21f1c956cc66eda61ddb *man/SeuratCommand-class.Rd e8fb5c0410c92ce49b4457e0eb9334c6 *man/SeuratObject-options.Rd d73717416176e98873bb399af5b09e12 *man/SeuratObject-package.Rd edf20dfee7d410b62aafee1ea928cb11 *man/Simplify.Rd 725038841e40bc6c46b3a46592854696 *man/SparseEmptyMatrix.Rd 9f986dc2f6897480228f9930a452b453 *man/SpatialImage-class.Rd 1e389e0be0b8bc1e609bf5abc580be44 *man/SpatialImage-methods.Rd 241621fd3f0fe0f62a93a5786a4de2c2 *man/SplitLayers.Rd c5805924129e581bdc52fc2c2de9d628 *man/StdAssay-class.Rd 65217df5efef01d5bc748857f7024340 *man/StdAssay-validity.Rd bc3fff87c216edc4c6b75b53d10853c4 *man/Stdev.Rd 841c737791dd2c167aab5d929dee1f1d *man/StitchMatrix.Rd 986bc41d6271e81be372b6dcd682b6be *man/Theta.Rd 3817b897b8bf6d4fdbeb7b109206e239 *man/Tool.Rd 48112d2a7d0050ec015c39a83a0995f4 *man/UpdateSeuratObject.Rd d3b9532593bad8d34b1230b91a7076b3 *man/UpdateSlots.Rd 1559af011a63bf6d5b42e8574fa88d47 *man/VariableFeatures-StdAssay.Rd 12bd753be49b15cfa2441b3d07192c0b *man/VariableFeatures.Rd 8269fce700ed6f00553001c1af49c5b4 *man/Version.Rd 1b5bf4a5af0c68d4c15001ccde0dec35 *man/WhichCells.Rd b5b10d13c6a18e29d6810d672ab3b32c *man/aggregate.Rd 1705d383070b935da9650bc22f9c0601 *man/angles.Rd 4b594f0e4406c304896977bdd211ce7c *man/as.Centroids.Rd a2a16136a75f8a639c3ac5e2f69ee58e *man/as.Graph.Rd be76dc90b5718f9de3394866eb682c79 *man/as.Neighbor.Rd 7bee3cbf07c3aff6aee7c12363a47a98 *man/as.Seurat.Rd 0b8d3c543ae03f20c3d930043178005c *man/as.list.SeuratCommand.Rd 06ad0e7708916f5018b604806d204f75 *man/as.matrix.LogMap.Rd b8849e9494481f71b2b40af8e4600a9d *man/as.sparse.Rd e803dab0c7f3b71a7ff2d7644917faab *man/cash-.Assay.Rd 8dbda0a18c6b12706d4771361bc265b1 *man/cash-.Assay5.Rd 202546036848ecab5a5770e130917c23 *man/cash-.Seurat.Rd 056a2e8aa3fb9b56c14974c6a15cac5c *man/cash-.SeuratCommand.Rd 0b135d429c603b2157cb402de5886ab5 *man/cash-.StdAssay.Rd fb38df81ba5ddd9bad8e0320aff0cf0f *man/colMeans-Assay-method.Rd a879d3019b027241c63e2c3a9a823503 *man/colMeans-Seurat-method.Rd 57a0fd821d41345c0a316a69dcf7e309 *man/dim.Assay.Rd d4728edcb3c3255885254d5e6609eeb6 *man/dim.Assay5.Rd 25fe538fd5bc5b2851614d27f11c2914 *man/dim.DimReduc.Rd 40bef2be5035317120df0356b0ce0bbc *man/dim.Seurat.Rd 201f574c40a2ec249b1184b02e2377d9 *man/dim.StdAssay.Rd 20486b2bc67925a57ad993d85cb3ef33 *man/dimnames.Assay.Rd 303485b5cb52cd0e9a6fd2c564c31432 *man/dimnames.Assay5.Rd da5ab0f0ac690f68a7e5b08373a2be47 *man/dimnames.Seurat.Rd 7d577c3280ec86dab78020766e8678cc *man/dimnames.StdAssay.Rd eceb92c873565469e9ead6f8c183083e *man/dot-AssayClass.Rd 134e406c615399e9d128600b068c8e16 *man/dot-BPMatrixMode.Rd aadaa2f56fe92c33c691e729f1057d09 *man/dot-CalcN.Rd 23ae29d348a9e8b6e249ab51d25dbc4f *man/dot-CheckFmargin.Rd 931c376797bad9cfd258df00a37ea397 *man/dot-ClassPkg.Rd d1574a8e2be2ac89d10810d75ba5b7c5 *man/dot-Collections.Rd cc20714ba72d4bda89234770cce787e0 *man/dot-Contains.Rd 98b6de90c0959a12a68d8a59c12609a9 *man/dot-CreateStdAssay.Rd e218d264e9000d36a1af88913901b630 *man/dot-DefaultFOV.Rd e31a175bf2c8063ac42b6ea99eeab3ad *man/dot-Deprecate.Rd 82ed2de664928c4ee81caa20bef2880b *man/dot-DiskLoad.Rd cc4c79d451cbf8951dcd0577af3a7306 *man/dot-DollarNames.Assay.Rd cfb49855fbb20c2718ec4e6b12c4ab19 *man/dot-DollarNames.Assay5.Rd cad072ddec0b3991a1ec36169f401590 *man/dot-DollarNames.Seurat.Rd 1e7adc2f62962fcb43b019606b800230 *man/dot-DollarNames.SeuratCommand.Rd 28939cff9333ef99d998fe9820bfe197 *man/dot-DollarNames.StdAssay.Rd 5011c93eeb726d96b8f701bc102198d1 *man/dot-FileMove.Rd 19ae37f51856781db6dcde3b374aaabe *man/dot-FilePath.Rd 7a766bef4f5176ff8ded63f17533b5b1 *man/dot-FilterObjects.Rd 1738fb16192f58807ffcc6a290a4aa14 *man/dot-FindObject.Rd dbd2eeb234777cc6a65cbeff197f16b4 *man/dot-GetMethod.Rd e21522a4e17a3765d08a3b23401e114e *man/dot-IsFutureSeurat.Rd 7f94e51426e043f028171b7841675530 *man/dot-KeyPattern.Rd 17623543126669490b52e8509ae69ebe *man/dot-MARGIN.Rd 227d3a360cf37d995f883f05682c4338 *man/dot-PropagateList.Rd 9ea277752c8cc24596d1a71dcc99fe36 *man/dot-RandomKey.Rd d1f1debba7fd87ccc32f441e5e4c531d *man/dot-SelectFeatures.Rd f723698c1b2732efa316f750c0e7e127 *man/dot-SparseSlots.Rd 139a4c40952e40752da8a86962f45b72 *man/dot-Subobjects.Rd 4e202b780c802799467ff6d0a3561472 *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 5779b2c103562bba92bbaa96df1cf4e1 *man/intersect.LogMap.Rd fca9737314fd0199d362a7f8a2a706ab *man/labels.LogMap.Rd 6399a87b50bf3da8a604857f858110f9 *man/merge.Assay.Rd 132073a6389718a2914c351302ea4e05 *man/merge.Assay5.Rd 72b3923ee07f8a70ea921d6111f2dc4d *man/merge.DimReduc.Rd 4657ad914b9579be715e473e09db4744 *man/merge.Seurat.Rd a7b4b0848ae01b811514eb70cb7fdb1e *man/merge.StdAssay.Rd a01937434391f7ca57fa96d817b7208e *man/names.Seurat.Rd 64d34a1389e7dba2ee903bdec04bc885 *man/old-assign.Rd 87e6d64f9d8a69f1a4ac581994aed2c8 *man/oldseurat-class.Rd 9cfc62f23870c0ecc67a04874a40c95c *man/pbmc_small.Rd 054a090d975920583551bc42d0c38186 *man/print.DimReduc.Rd 685fad16b29908921cbad9bacf301fad *man/reexports.Rd 1a675acb987424197f555d00a14e0c5f *man/roxygen/meta.R 456b8debeb51240fbac6fbd10cae4a43 *man/roxygen/templates/desc-validity.R 1346a8d14db128f7ca35912f75fd7f92 *man/roxygen/templates/lifecycle-deprecated.R 404928f1ee02ea0ba1761f3ee3acfe2d *man/roxygen/templates/lifecycle-experimental.R 5f790d05f43a8fcf25e70ff12cca173c *man/roxygen/templates/lifecycle-superseded.R a40fd1b0f21877d53380e0594aa7c199 *man/roxygen/templates/method-cells.R 718f742916c41de42a6df89ee6e785e8 *man/roxygen/templates/method-features.R 841460c9450389a36973a871acd6be46 *man/roxygen/templates/method-lengths.R 8584e3cf8526cfe5a364174bf55f01af *man/roxygen/templates/method-show.R 18eb06f32e6831147e37d5262d4a52df *man/roxygen/templates/method-stdassay.R 0eb6f7d6c6aa55ee2076656cdfd18d9e *man/roxygen/templates/name-oldv.R b7571c6eeed7832b81c396f006acbccd *man/roxygen/templates/note-reqdpkg.R 0e2541fd69d14b463f53d87b37d36036 *man/roxygen/templates/param-dots-ignored.R c0b662ef6b88e24401e81d72a8fb425e *man/roxygen/templates/param-dots-method.R e0941d4caea9574a267c4583c10e118d *man/roxygen/templates/param-verbose.R 3ffa0ffd5ca246fce23873bb416c402a *man/roxygen/templates/return-null.R 07f7a044548e870f228b6845f5845dc7 *man/roxygen/templates/return-show.R 69b32a9f290e22f13f9ad87ae2d746de *man/roxygen/templates/section-future.R 8e4b4e6825cb2c6afcbc133292c583af *man/roxygen/templates/section-progressr.R b0eaf1e923a3813401e1fdb3f0bbec5f *man/roxygen/templates/seealso-methods.R a7c4f801269c8d50d5e61d0328d52418 *man/roxygen/templates/slot-key.R 1ee7d3e493b42206c8f00a876eaa55c5 *man/roxygen/templates/slot-misc.R ac9cd974a57069d7fd7e1b61d2e1bc40 *man/roxygen/templates/slot-stdassay.R 8bf2ea02a8ef005e0ca4ccbcd94dc51a *man/s4list.Rd e631fa7517726bd8dc4766837e10ccd1 *man/set-if-na.Rd d74ed125dd6047cc75ac2ed5a37db883 *man/set-if-null.Rd 7b6a9c668436221cdccfdbd9772903c0 *man/show-Assay-method.Rd 2f3d8f7ae4a4651afa955e6f9b283bae *man/show-DimReduc-method.Rd 8effa1eb4a9d60f28a286281410a6ab8 *man/show-Graph-method.Rd edfb29e0c3a620256fb0296b62f33f3d *man/show-LogMap-method.Rd 1c5db6ed330756ba2d21f9b7d71aab37 *man/show-Seurat-method.Rd ed63ba5499f7fce6a772d8d0a184f160 *man/show-SeuratCommand-method.Rd e5b86437cd8370ef3e3cea64d3b6b454 *man/show-StdAssay-method.Rd c04c25e1058f0ba89ecc36232aec6a28 *man/show-oldseurat-method.Rd d6eb2bc98689310c045dea51bac24577 *man/split.Assay.Rd e1e373c8d21a91bac21409f8f3654545 *man/split.Assay5.Rd e248a59adcfad8462c806020fc01a203 *man/split.Seurat.Rd 1f6133efa84751c08e45220973028d3c *man/split.StdAssay.Rd ead359320b4e9a43df5609ae5c473212 *man/sub-.Assay.Rd f90fa6e32497ac8d26758b41ee93c44e *man/sub-.Assay5.Rd c34dc3b44e1568810d0bba61025fe4d7 *man/sub-.DimReduc.Rd cc3bf4e91c1d775027f9afbad6d0c080 *man/sub-.SeuratCommand.Rd b0bfd507155c2d70c2f23debb8337e29 *man/sub-.StdAssay.Rd 4d079cf62bcb8d79485d894328da4c29 *man/sub-LogMap-method.Rd 7dcca9bf52e187ff10d97650264b6c07 *man/sub-sub-.Assay.Rd 34ec2da01d4330865737568687ebb01e *man/sub-sub-.Assay5.Rd 99109a1307c05f56b635d2c13995618b *man/sub-sub-.DimReduc.Rd 831a9d59da9baa648940766d6fcb3716 *man/sub-sub-.Seurat.Rd 37c9097d491e5db7c24611c65a7aabbc *man/sub-sub-.StdAssay.Rd 03cf05b28769296fdb5080874a5adb4f *man/sub-sub-LogMap-internal-method.Rd f0c76402f6e588a99359d5d7f7958367 *man/sub-subset-Seurat-NULL.Rd 555de8cc5c9a624c824f937b17ecf3a5 *man/sub-subset-Seurat-character-missing-StdAssay-method.Rd ce355fbeb81c37610afa54e86259589e *man/sub-subset-Seurat.Rd 855d417e0aea5019b89e587fbb503503 *man/subset.Assay.Rd 3d3c322f6e5da4d771b754f19aef6a00 *man/subset.Assay5.Rd 1f73ea9d76b418e0cd08f2f6425cdaa9 *man/subset.DimReduc.Rd f2d66184c4393ddd8725766f9e4a48bb *man/subset.Seurat.Rd c97ee76f2b74bbd062556ea1a0890671 *man/subset.StdAssay.Rd a03895c9b6127878dc1b4b99ce3257d0 *man/v5-assay-summaries.Rd 48564b53bdf7cadfa2a1cf088e08fa1a *src/RcppExports.cpp 288fcd4e7664587a425de78708c7f251 *src/data_manipulation.cpp f99ccc0ef8d6bb241950e293d697668f *src/data_manipulation.h f33c09d14c160d9f29a89251fd91a036 *src/valid_pointer.c