Skip to main content
Glama

embedding_density

Calculate cell density in single-cell RNA sequencing embeddings to identify high-density regions and analyze spatial patterns in data visualizations.

Instructions

Calculate the density of cells in an embedding

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
basisNoThe embedding over which the density will be calculated. This embedded representation should be found in `adata.obsm['X_[basis]']`.umap
groupbyNoKey for categorical observation/cell annotation for which densities are calculated per category.
key_addedNoName of the `.obs` covariate that will be added with the density estimates.
componentsNoThe embedding dimensions over which the density should be calculated. This is limited to two components.

Implementation Reference

  • Generic handler function for tl tools, including embedding_density, that dispatches to sc.tl.embedding_density with inspected parameters and logs the operation.
    def run_tl_func(ads, func, arguments):
        adata = ads.adata_dic[ads.active]
        if func not in tl_func:
            raise ValueError(f"Unsupported function: {func}")
        run_func = tl_func[func]
        parameters = inspect.signature(run_func).parameters
        kwargs = {k: arguments.get(k) for k in parameters if k in arguments}    
        try:
            res = run_func(adata, **kwargs)
            add_op_log(adata, run_func, kwargs)
        except Exception as e:
            logger.error(f"Error running function {func}: {e}")
            raise
        return 
  • Pydantic input schema model for the embedding_density computation tool (sc.tl.embedding_density).
    class EmbeddingDensityModel(JSONParsingModel):
        """Input schema for the embedding density calculation tool."""
        
        basis: str = Field(
            default='umap',
            description="The embedding over which the density will be calculated. This embedded representation should be found in `adata.obsm['X_[basis]']`."
        )
        groupby: Optional[str] = Field(
            default=None,
            description="Key for categorical observation/cell annotation for which densities are calculated per category."
        )
        key_added: Optional[str] = Field(
            default=None,
            description="Name of the `.obs` covariate that will be added with the density estimates."
        )
        components: Optional[Union[str, List[str]]] = Field(
            default=None,
            description="The embedding dimensions over which the density should be calculated. This is limited to two components."
        )
        
        @field_validator('components')
        def validate_components(cls, v: Optional[Union[str, List[str]]]) -> Optional[Union[str, List[str]]]:
            """Validate that components are limited to two dimensions"""
            if v is not None and isinstance(v, list) and len(v) > 2:
                raise ValueError("components is limited to two dimensions")
            return v
  • Registration of the embedding_density tool for computation (tl), including tool object creation, function mapping in tl_func, and inclusion in tl_tools dictionary.
    # Add embedding_density tool
    embedding_density_tool = types.Tool(
        name="embedding_density",
        description="Calculate the density of cells in an embedding",
        inputSchema=EmbeddingDensityModel.model_json_schema(),
    )
    
    # Add leiden tool
    leiden_tool = types.Tool(
        name="leiden",
        description="Leiden clustering algorithm for community detection",
        inputSchema=LeidenModel.model_json_schema(),
    )
    
    # Add louvain tool
    louvain_tool = types.Tool(
        name="louvain",
        description="Louvain clustering algorithm for community detection",
        inputSchema=LouvainModel.model_json_schema(),
    )
    
    # Add dendrogram tool
    dendrogram_tool = types.Tool(
        name="dendrogram",
        description="Hierarchical clustering dendrogram",
        inputSchema=DendrogramModel.model_json_schema(),
    )
    
    # Add dpt tool
    dpt_tool = types.Tool(
        name="dpt",
        description="Diffusion Pseudotime (DPT) analysis",
        inputSchema=DPTModel.model_json_schema(),
    )
    
    # Add paga tool
    paga_tool = types.Tool(
        name="paga",
        description="Partition-based graph abstraction",
        inputSchema=PAGAModel.model_json_schema(),
    )
    
    # Add ingest tool
    ingest_tool = types.Tool(
        name="ingest",
        description="Map labels and embeddings from reference data to new data",
        inputSchema=IngestModel.model_json_schema(),
    )
    
    # Add rank_genes_groups tool
    rank_genes_groups_tool = types.Tool(
        name="rank_genes_groups",
        description="Rank genes for characterizing groups, perform differentially expressison analysis",
        inputSchema=RankGenesGroupsModel.model_json_schema(),
    )
    
    # Add filter_rank_genes_groups tool
    filter_rank_genes_groups_tool = types.Tool(
        name="filter_rank_genes_groups",
        description="Filter out genes based on fold change and fraction of genes",
        inputSchema=FilterRankGenesGroupsModel.model_json_schema(),
    )
    
    # Add marker_gene_overlap tool
    marker_gene_overlap_tool = types.Tool(
        name="marker_gene_overlap",
        description="Calculate overlap between data-derived marker genes and reference markers",
        inputSchema=MarkerGeneOverlapModel.model_json_schema(),
    )
    
    # Add score_genes tool
    score_genes_tool = types.Tool(
        name="score_genes",
        description="Score a set of genes based on their average expression",
        inputSchema=ScoreGenesModel.model_json_schema(),
    )
    
    # Add score_genes_cell_cycle tool
    score_genes_cell_cycle_tool = types.Tool(
        name="score_genes_cell_cycle",
        description="Score cell cycle genes and assign cell cycle phases",
        inputSchema=ScoreGenesCellCycleModel.model_json_schema(),
    )
    
    # Dictionary mapping tool names to scanpy functions
    tl_func = {
        "tsne": sc.tl.tsne,
        "umap": sc.tl.umap,
        "draw_graph": sc.tl.draw_graph,
        "diffmap": sc.tl.diffmap,
        "embedding_density": sc.tl.embedding_density,
        "leiden": sc.tl.leiden,
        "louvain": sc.tl.louvain,
        "dendrogram": sc.tl.dendrogram,
        "dpt": sc.tl.dpt,
        "paga": sc.tl.paga,
        "ingest": sc.tl.ingest,
        "rank_genes_groups": sc.tl.rank_genes_groups,
        "filter_rank_genes_groups": sc.tl.filter_rank_genes_groups,
        "marker_gene_overlap": sc.tl.marker_gene_overlap,
        "score_genes": sc.tl.score_genes,
        "score_genes_cell_cycle": sc.tl.score_genes_cell_cycle,
    }
    
    # Dictionary mapping tool names to tool objects
    tl_tools = {
        "tsne": tsne_tool,
        "umap": umap_tool,
        "draw_graph": draw_graph_tool,
        "diffmap": diffmap_tool,
        "embedding_density": embedding_density_tool,
  • Generic handler function for pl tools, including embedding_density plot, that calls sc.pl.embedding_density, saves figure, and logs.
    def run_pl_func(ads, func, arguments):
        """
        Execute a Scanpy plotting function with the given arguments.
        
        Parameters
        ----------
        adata : AnnData
            Annotated data matrix.
        func : str
            Name of the plotting function to execute.
        arguments : dict
            Arguments to pass to the plotting function.
            
        Returns
        -------
        The result of the plotting function.
        """
        adata = ads.adata_dic[ads.active]
        if func not in pl_func:
            raise ValueError(f"Unsupported function: {func}")
    
        run_func = pl_func[func]
        parameters = inspect.signature(run_func).parameters
        kwargs = {k: arguments.get(k) for k in parameters if k in arguments}    
    
        if "title" not in parameters:
            kwargs.pop("title", False)    
        kwargs.pop("return_fig", True)
        kwargs["show"] = False
        kwargs["save"] = ".png"
        try:
            fig = run_func(adata, **kwargs)
            fig_path = set_fig_path(func, **kwargs)
            add_op_log(adata, run_func, kwargs)
            return fig_path 
        except Exception as e:
            raise e
        return fig_path
  • Pydantic input schema model for the embedding_density plotting tool (sc.pl.embedding_density), extending BaseEmbeddingModel.
    class EmbeddingDensityModel(BaseEmbeddingModel):
        """Input schema for the embedding_density plotting tool."""
        
        basis: str = Field(
            ...,  # Required field
            description="Basis to use for embedding."
        )
        
        key: Optional[str] = Field(
            default=None,
            description="Key for annotation of observations/cells or variables/genes."
        )
        
        convolve: Optional[float] = Field(
            default=None,
            description="Sigma for Gaussian kernel used for convolution."
        )
        
        alpha: float = Field(
            default=0.5,
            description="Alpha value for the plot.",
            ge=0,
            le=1
        )
        
        @field_validator('alpha')
        def validate_alpha(cls, v: float) -> float:
            """Validate alpha is between 0 and 1"""
            if v < 0 or v > 1:
                raise ValueError("alpha must be between 0 and 1")
            return v
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden of behavioral disclosure. It states the tool calculates density but doesn't explain what 'density' means in this context, how it's computed, whether it modifies data in place (e.g., adding results to `.obs`), or any performance considerations. This is inadequate for a tool with no annotation coverage.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, clear sentence: 'Calculate the density of cells in an embedding.' It's front-loaded with the core purpose and wastes no words, making it highly efficient and easy to parse for an AI agent.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity of a density calculation tool with 4 parameters and no output schema, the description is incomplete. It doesn't explain the output format (e.g., where results are stored, like in `.obs` as hinted by the 'key_added' parameter), nor does it cover behavioral aspects like data mutation. This leaves significant gaps for an agent to understand the tool's full context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has 100% description coverage, so the schema already documents all parameters thoroughly. The description doesn't add any semantic details beyond what's in the schema, such as explaining interactions between parameters or typical use cases. This meets the baseline for high schema coverage but doesn't enhance understanding.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Calculate the density of cells in an embedding.' It specifies the verb ('calculate') and resource ('density of cells'), making the function unambiguous. However, it doesn't differentiate from sibling tools like 'pl_embedding' or 'umap', which might also involve embeddings, so it doesn't reach a perfect score.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. It doesn't mention any prerequisites, such as needing an existing embedding from tools like 'umap' or 'tsne', nor does it compare to sibling tools like 'pl_embedding' for visualization purposes. This leaves the agent without context for tool selection.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/huang-sh/scmcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server