Metadata-Version: 2.5
Name: scsketch
Version: 0.3.0
Summary: Interactive exploration of single-cell embeddings with directional analysis
Project-URL: Homepage, https://github.com/colabobio/scsketch
Project-URL: Repository, https://github.com/colabobio/scsketch
Project-URL: Bug Tracker, https://github.com/colabobio/scsketch/issues
Author-email: Askar Temirbek <askar.temirbek@umassmed.edu>, Fritz Lekschas <code@lekschas.de>, Kris Sankaran <ksankaran@wisc.edu>, Andres Colubri <andres.colubri@umassmed.edu>
License: MIT
Keywords: bioinformatics,jupyter,single-cell,visualization,widget
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
Classifier: Topic :: Scientific/Engineering :: Visualization
Requires-Python: >=3.10
Requires-Dist: anndata>=0.10.0
Requires-Dist: anywidget>=0.9.0
Requires-Dist: ipywidgets>=8.0.0
Requires-Dist: jupyter-scatter<1.0.0,>=0.21.0
Requires-Dist: matplotlib>=3.7.0
Requires-Dist: numpy>=1.24.0
Requires-Dist: pandas>=2.0.0
Requires-Dist: pooch>=1.7.0
Requires-Dist: requests>=2.28.0
Requires-Dist: scanpy>=1.9.0
Requires-Dist: scipy>=1.11.0
Requires-Dist: traitlets>=5.0.0
Provides-Extra: dev
Requires-Dist: debugpy>=1.8.0; extra == 'dev'
Requires-Dist: jupyterlab>=4.0.0; extra == 'dev'
Requires-Dist: numba>=0.57.0; extra == 'dev'
Requires-Dist: pytest; extra == 'dev'
Requires-Dist: ruff; extra == 'dev'
Requires-Dist: watchfiles>=0.20.0; extra == 'dev'
Provides-Extra: fast
Requires-Dist: numba>=0.57.0; extra == 'fast'
Description-Content-Type: text/markdown

# scSketch project

scSketch is an interactive exploration tool of single-cell embeddings (UMAP, tSNE, etc.) for Python notebooks. It is based on the [jupyter-scatter widget](https://jupyter-scatter.dev/) by [Fritz Lekschas](https://lekschas.de/) and it reimplements some features of the earlier [SciViewer visualizer](https://github.com/colabobio/sciviewer). 

scSketch allows users to explore embeddings by selecting linear directions and cells of interest to see the genes/proteins that are changing the most among the selected cells and direction. It then allows users to see what biological pathways the genes/proteins are a part of (by connecting to Reactome database) and provides users with the diagram of biological pathways where users can see their gene/protein of interest and what other genes/proteins/molecules they interact with. The widget can handle millions of points and supports view linking.

<p align="center">
  <img src="docs/assets/dir_analysis_demo.gif" alt="scSketch directional analysis demo" width="900" />
</p>
<p align="center">
  <em>Directional sketch → compute directional analysis → click a gene for pathway context.</em>
</p>

<p align="center">
  <img src="docs/assets/diff_exp_analysis_demo.gif" alt="scSketch differential expression demo" width="900" />
</p>
<p align="center">
  <em>Select two groups → compute differential expression → browse results.</em>
</p>

## Usage

### Quick Start

The easiest way to try scSketch is with the built-in demo (no installation required):

```bash
uvx scsketch demo
```

This single command will automatically install scSketch and all dependencies in an ephemeral environment, then launch the demo notebook. It requires [uv](https://docs.astral.sh/uv/), which is a fast Python package manager.

If the demo fails with `ModuleNotFoundError: No module named 'jscatter.widgets'`,
your environment resolved `jupyter-scatter` 1.x, which removed the helper module
used by this scSketch release. Run the demo with the compatible 0.x line:

```bash
uvx --isolated --with "jupyter-scatter<1" scsketch demo
```

Alternatively, if you've cloned the repository, you can run the demo notebook directly with [juv](https://github.com/manzt/juv):

```bash
git clone https://github.com/colabobio/scsketch.git
cd scsketch
uvx juv run demo.ipynb
```

Then use in any notebook:

```python
from scsketch import ScSketch

sketch = ScSketch(adata=...)
sketch.show()
```

See the demo notebook for more details

### Use scSketch in your own notebook

scSketch requires **Python 3.10 or later**. Before installing, make sure your environment meets this requirement:

```bash
python --version   # should print Python 3.10.x or higher
```

If you are using conda and need to create or upgrade an environment:

```bash
# Create a new environment with the right Python version
conda create -n my-env python=3.10
conda activate my-env
```

Then install scSketch into the environment backing your Jupyter kernel:

```bash
pip install scsketch
```

If importing scSketch fails with `ModuleNotFoundError: No module named 'jscatter.widgets'`,
install a compatible `jupyter-scatter` release in the same environment:

```bash
pip install "jupyter-scatter>=0.21,<1"
```

**Optional: Numba-accelerated kernels (`[fast]` extra)**

Differential expression computations can be significantly accelerated by [Numba](https://numba.pydata.org/). Numba is an optional dependency — scSketch works without it, but automatically uses it when available. To install with Numba:

```bash
pip install "scsketch[fast]"
```

> **Note:** If you install scSketch into a conda environment, make sure you also have JupyterLab installed *in that same environment* so the kernel picks up the right packages:
> ```bash
> pip install jupyterlab
> jupyter lab
> ```

Then in a notebook:

```python
import scanpy as sc
from scsketch import ScSketch

adata = sc.read_h5ad("my_data.h5ad")

# scSketch currently reads coordinates from `adata.obsm["X_umap"]`.
# If you have a different embedding (e.g. tSNE), you can copy it into `X_umap`:
# adata.obsm["X_umap"] = adata.obsm["X_tsne"]

sketch = ScSketch(
    adata=adata,
    metadata_cols=["louvain"],   # optional: columns in `adata.obs` for coloring
    color_by_default="louvain",  # optional: which metadata to color by initially
)

# If this isn't the last line in the cell, use: `from IPython.display import display; display(sketch.show())`
sketch.show()
```

**Directional Search: keep brush selections roughly linear**

Directional Search reduces your selection to a 1D “along-the-sketch” axis by projecting cells onto a single direction vector. If your brush selection is very curved, loops back, or spans multiple branches/blobs, that 1D projection can mix multiple directions of variation and produce hard-to-interpret results.

Practical tips:

- Sketch along one clear gradient at a time (a selection closer to a straight line works best).
- If the trajectory bends, split it into multiple shorter selections and compare results.

**Optional multi-view panel**

You can pass additional prebuilt `jupyter-scatter` views to compare the same selected cells across embeddings such as PCA, tSNE, or PHATE. Extra views are matched to scSketch by row index, so build them from the same cells in the same order as `adata`.

```python
import pandas as pd
from jscatter import Scatter

pca_df = pd.DataFrame(
    {
        "PC1": adata.obsm["X_pca"][:, 0],
        "PC2": adata.obsm["X_pca"][:, 1],
        "louvain": adata.obs["louvain"].astype(str).to_numpy(),
    },
    index=adata.obs_names,
)

pca = Scatter(data=pca_df, x="PC1", y="PC2", color_by="louvain", axes=True)

sketch = ScSketch(
    adata=adata,
    metadata_cols=["louvain"],
    color_by_default="louvain",
    extra_views={"PCA": pca},
)
sketch.show()
```

When extra views are provided, scSketch shows a **Multi-view** OFF/ON toggle in the right panel. ON keeps the extra view visible in a compact square panel; OFF restores the usual gene detail panel for expression-vs-projection, DE violin, and pathway views. Result-table gene clicks recolor both the main scSketch embedding and the extra views by the same expression vector, which helps compare whether a directional expression pattern is preserved across embeddings.


**Gene IDs vs gene symbols**

scSketch keeps `adata.var_names` as the gene identifier used for expression lookup, session replay, and exported `p-value` results. In result tables, it automatically displays a more readable label when `adata.var` or `adata.raw.var` contains one of these columns: `gene_short_name`, `gene_symbols`, `gene_symbol`, `gene_name`, `gene_names`, or `symbol`.

For example, a dataset with `WBGene...` IDs in `adata.var_names` and readable names in `adata.var["gene_short_name"]` will show the readable names in the UI while still using the original `WBGene...` IDs internally.

### Using scSketch with uv / uvx

Here are the recommended ways to integrate scSketch when using uv / uvx.

**Add to an existing `uv` project:**

```bash
uv add scsketch          # base install
uv add "scsketch[fast]"  # with Numba-accelerated kernels (recommended)
uv run jupyter lab
```

**Standalone notebook with `juv`:**

[juv](https://github.com/manzt/juv) runs notebooks in isolated environments defined by inline metadata — no `pyproject.toml` needed.

```bash
# Add scsketch to an existing notebook (writes inline dependency metadata)
uvx juv add my_notebook.ipynb "scsketch[fast]"

# Launch it in an auto-provisioned environment
uvx juv run my_notebook.ipynb
```

The notebook becomes fully self-contained and reproducible: anyone with `juv` can run it without any prior setup.

**Try the built-in demo without installing anything:**

```bash
uvx scsketch demo
```

This uses `uvx` to run scSketch ephemerally — nothing is permanently installed in your environment.

### Running the original notebook with juv

To run the original inline notebook, first install [juv](https://github.com/manzt/juv) and then call:

```bash
juv run demo.ipynb
```

## Development

This project uses [uv](https://docs.astral.sh/uv/) for development and dependency management.

### Setup

1.  **Clone the repository:**
    ```sh
    git clone https://github.com/colabobio/scsketch.git
    cd scsketch
    ```

2.  **Sync environment (installs dependencies):**
    ```sh
    uv sync
    ```

### Development Workflow

You can run commands inside the project's environment using `uv run`.

*   **Launch Jupyter Lab for testing:**
    ```sh
    uv run jupyter lab
    ```
    Open `debug.ipynb` to test changes.

*   **Hot-reloading JS/CSS:**
    The `debug.ipynb` notebook is pre-configured with `ANYWIDGET_HMR=1`.
    Any changes you save to files in `src/scsketch/static/` will legally update the widget in your browser without reloading the page.

*   **Linting (Ruff):**
    ```sh
    uv run ruff check .
    ```

*   **Testing:**
    Run the unit test suite with `pytest`:
    ```sh
    uv run pytest tests/
    ```

### Optional: Manual Activation

If you prefer to activate the environment in your shell:
```sh
source .venv/bin/activate
# Now you can use `jupyter`, `python`, `pip` directly
jupyter lab
```

Or with editable installs:

```sh
python -m venv .venv
source .venv/bin/activate
python -m pip install -e ".[dev,fast]"
jupyter lab demo.ipynb
```

### Debugging with VS Code

To debug the Python side of your widgets step-by-step:

1.  **Debugging Jupyter Notebooks:**
    *   Open `debug.ipynb` in VS Code.
    *   Click the **"Select Kernel"** button at the top right and select your project environment (e.g., `.venv` or the one created by `uv`).
    *   You can set breakpoints directly in the notebook cells or in the python files (`src/scsketch/widgets/*.py`).
    *   To debug code in external files (like the widgets), use the **"Debug Cell"** option (often found in the dropdown menu next to the run button of a cell).

2.  **Attaching to a running kernel:**
    If you prefer using `jupyter lab` in your browser but want to debug Python code in VS Code:
    *   Run `jupyter lab` (e.g., `uv run jupyter lab`).
    *   Add this code to a cell at the beginning of your notebook:
        ```python
        import debugpy
        debugpy.listen(5678)
        print("Waiting for debugger attach...")
        debugpy.wait_for_client()
        print("Debugger attached")
        ```
    *   In VS Code, go to the **Run and Debug** view (Ctrl+Shift+D).
    *   Select **"Python: Attach to Local Process"** from the dropdown and click the Play button.
    *   VS Code will attach to your running kernel, and you can now use breakpoints in your local Python files.

### Debugging Frontend (JavaScript)

Since the widgets run in the web browser (or VS Code's webview), you need to use browser developer tools to debug the JavaScript code (`src/scsketch/static/*.js`).

1.  **Run the widget:** Open `debug.ipynb` and run the cell that displays the widget.
2.  **Open Developer Tools:**
    *   **In Browser (Jupyter Lab):** Right-click anywhere on the page > **Inspect**.
    *   **In VS Code:** Open the command palette (`Cmd+Shift+P`) and run **"Developer: Open Webview Developer Tools"**.
3.  **Find your source:**
    *   Go to the **Sources** tab in the developer tools.
    *   Use `Cmd+P` (Mac) or `Ctrl+P` (Windows/Linux) to search for your file (e.g., `correlation_table.js`).
    *   *Note: Because of how modules are loaded, the file path might look like `localhost:xyz/.../correlation_table.js`.*
4.  **Set Breakpoints:** Click on the line number in the JS file to set a breakpoint.
5.  **Trigger the code:** Interact with the widget in the notebook. The debugger will pause on your breakpoint, allowing you to inspect variables and step through the code.

### Publish a New Version

To bump the version use one of the following commands:

1. `uvx bump-my-version bump minor` (e.g., v0.1.0 → v0.2.0)
2. `uvx bump-my-version bump patch` (e.g., v0.1.0 → v0.1.1)
3. `uvx bump-my-version bump major` (e.g., v0.1.0 → v1.0.0)

Afterward do `git push --follow-tags`. Github actions will handle the rest.
