---
title: "Vector Field Analysis and Visualization"
author: "Zaoqu Liu"
date: "`r Sys.Date()`"
output: 
  rmarkdown::html_vignette:
    toc: true
    toc_depth: 3
    fig_width: 8
    fig_height: 6
vignette: >
  %\VignetteIndexEntry{Vector Field Analysis and Visualization}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.align = "center",
  message = FALSE,
  warning = FALSE
)
```

## Introduction

One of the most powerful features of CellODE is its ability to infer and visualize **cellular velocity fields**. The vector field represents the instantaneous direction and magnitude of cellular state changes, providing insights into:

- Differentiation trajectories
- Cell fate decisions
- Developmental dynamics

This vignette demonstrates how to use CellODE's built-in functions for vector field analysis and visualization.

## Quick Start: Using CellODE Functions

```{r load-package}
library(CellODE)
library(ggplot2)
library(Seurat)
```

### Create Example Data

First, let's create a Seurat object with simulated trajectory data:

```{r create-data}
set.seed(42)
n_cells <- 500
n_genes <- 100

# Simulate trajectory
t_true <- seq(0, 1, length.out = n_cells)

# Create expression data (genes change along trajectory)
counts <- matrix(0, nrow = n_genes, ncol = n_cells)
for (i in 1:n_genes) {
    phase <- runif(1, 0, 2 * pi)
    amplitude <- runif(1, 3, 10)
    counts[i, ] <- rpois(n_cells, lambda = pmax(1, amplitude * (1 + sin(t_true * 2 * pi + phase))))
}
rownames(counts) <- paste0("Gene", seq_len(n_genes))
colnames(counts) <- paste0("Cell", seq_len(n_cells))

# Create Seurat object
srt <- CreateSeuratObject(counts = counts)

# Add UMAP embedding (curved trajectory)
umap1 <- t_true * 10 + rnorm(n_cells, sd = 0.5)
umap2 <- 4 * sin(t_true * 2 * pi) + rnorm(n_cells, sd = 0.3)

umap_embeddings <- matrix(c(umap1, umap2), ncol = 2)
rownames(umap_embeddings) <- colnames(srt)
colnames(umap_embeddings) <- c("UMAP_1", "UMAP_2")

srt[["umap"]] <- CreateDimReducObject(
    embeddings = umap_embeddings,
    key = "UMAP_",
    assay = "RNA"
)

# Add pseudotime
srt$pseudotime <- t_true + rnorm(n_cells, sd = 0.02)
srt$pseudotime <- pmax(0, pmin(1, srt$pseudotime))
```

### Simulate CellODE Model Output

In a real workflow, you would train a CellODE model. Here we simulate the output:

```{r simulate-model}
# Simulate latent space (normally from model output)
n_latent <- 5
zs <- matrix(rnorm(n_cells * n_latent), ncol = n_latent)

# Make latent space correlate with trajectory
zs[, 1] <- t_true * 2 + rnorm(n_cells, sd = 0.2)
zs[, 2] <- sin(t_true * pi) + rnorm(n_cells, sd = 0.1)
rownames(zs) <- colnames(srt)

# Simulate vector field in latent space
vf <- matrix(0, nrow = n_cells, ncol = n_latent)
vf[, 1] <- 1 + rnorm(n_cells, sd = 0.1)  # Constant velocity in z1
vf[, 2] <- cos(t_true * pi) * pi / 2 + rnorm(n_cells, sd = 0.1)  # Derivative of sin
rownames(vf) <- colnames(srt)

# Store in Seurat object (as CellODE does)
srt@misc$X_zs <- zs
srt@misc$X_VF <- vf
```

## Vector Field Computation with CellODE

### Step 1: Compute Cosine Similarity

Use `cosine_similarity()` to compute transition probabilities in latent space:

```{r cosine-sim}
# Compute cosine similarity matrix
T_mat <- cosine_similarity(
    zs = zs,
    vf = vf,
    n_neigh = 20
)

cat("Transition matrix dimensions:", dim(T_mat), "\n")
cat("Non-zero entries:", sum(T_mat != 0), "\n")
```

### Step 2: Compute Embedding Velocity

Use `vector_field_embedding()` to project velocities to UMAP space:

```{r embed-velocity}
# Get embedding coordinates
E <- Embeddings(srt, "umap")

# Compute velocity in embedding space
V_embed <- vector_field_embedding(
    T_mat = T_mat,
    E = E,
    scale = 10
)

cat("Embedding velocity dimensions:", dim(V_embed), "\n")
cat("Mean velocity magnitude:", mean(sqrt(rowSums(V_embed^2))), "\n")
```

### Step 3: Grid-Based Vector Field

Use `vector_field_embedding_grid()` for cleaner visualization:

```{r grid-vf}
# Compute grid-based vector field
grid_result <- vector_field_embedding_grid(
    E = E,
    V = V_embed,
    smooth = 0.5,
    stream = FALSE,
    density = 1.0
)

cat("Grid points:", nrow(grid_result$E_grid), "\n")
```

## Visualization with CellODE

### Plot Pseudotime with Direction Arrows

Use `plot_pseudotime()` to visualize pseudotime with trajectory arrows:
 
```{r plot-pseudotime, fig.width=9, fig.height=6}
# Basic pseudotime plot
p1 <- plot_pseudotime(
    srt, 
    time_key = "pseudotime",
    arrow_show = TRUE,
    arrow_density = 1.5,
    point_palette = "Spectral",
    title = "Pseudotime with Direction Arrows"
)
print(p1)
```

### Plot Vector Field - Grid Mode

Use `plot_vector_field()` with grid mode for clean visualization:

```{r plot-vf-grid, fig.width=9, fig.height=6}
# Vector field - grid mode
p2 <- plot_vector_field(
    srt,
    plot_type = "grid",
    color_by = "pseudotime",
    arrow_density = 0.8,
    arrow_color = "grey20",
    point_palette = "Spectral",
    title = "Vector Field (Grid Mode)"
)
print(p2)
```

### Plot Vector Field - Stream Mode

Stream mode provides colored arrows based on velocity magnitude:

```{r plot-vf-stream, fig.width=9, fig.height=6}
# Vector field - stream mode with colored arrows
p3 <- plot_vector_field(
    srt,
    plot_type = "stream",
    color_by = "pseudotime",
    arrow_density = 1.2,
    point_palette = "viridis",
    title = "Vector Field (Stream Mode)"
)
print(p3)
```

### Plot Vector Field - Raw Mode

Raw mode shows arrows at each cell position:

```{r plot-vf-raw, fig.width=9, fig.height=6}
# Vector field - raw mode (per-cell arrows)
p4 <- plot_vector_field(
    srt,
    plot_type = "raw",
    color_by = "pseudotime",
    arrow_density = 0.3,  # Subsample for clarity
    arrow_color = "navy",
    point_palette = "magma",
    title = "Vector Field (Raw Mode)"
)
print(p4)
```

## Customization Options

### Arrow Styling

```{r arrow-styles, fig.width=9, fig.height=6}
# Custom arrow styling
p_custom <- plot_vector_field(
    srt,
    plot_type = "grid",
    color_by = "pseudotime",
    arrow_type = "closed",  # Filled arrowheads
    arrow_color = "#E63946",  # Red arrows
    arrow_density = 0.6,
    arrow_length = 0.2,
    arrow_width = 0.8,
    arrow_angle = 30,
    point_palette = "RdYlBu",
    point_size = 0.8,
    title = "Custom Arrow Styling"
)
print(p_custom)
```

### Clean Publication Figure

```{r publication-fig, fig.width=9, fig.height=6}
# Clean figure for publication
p_pub <- plot_pseudotime(
    srt,
    time_key = "pseudotime",
    arrow_show = TRUE,
    arrow_density = 1.0,
    arrow_type = "open",
    arrow_color = "black",
    point_palette = "viridis",
    point_size = 1.2,
    show_axes = FALSE,
    title = NULL
)
print(p_pub)
```

## Mathematical Background

### From Latent Dynamics to Velocity

The Neural ODE in CellODE defines the velocity in latent space:

$$\mathbf{v}_\text{latent}(t) = \frac{d\mathbf{z}}{dt} = f_\theta(\mathbf{z}(t), t)$$

### Cosine Similarity

The `cosine_similarity()` function computes:

$$\text{cos\_sim}_{ij} = \frac{\mathbf{v}_i \cdot (\mathbf{z}_j - \mathbf{z}_i)}{||\mathbf{v}_i|| \cdot ||\mathbf{z}_j - \mathbf{z}_i||}$$

### Transition Probability

The transition probabilities are computed as:

$$T_{ij} = \text{sign}(\text{cos\_sim}_{ij}) \cdot (\exp(|\text{cos\_sim}_{ij}| \cdot s) - 1)$$

### Embedding Velocity

The `vector_field_embedding()` function computes:

$$\mathbf{v}_i^\text{embed} = \sum_j T_{ij} \cdot \frac{\mathbf{e}_j - \mathbf{e}_i}{||\mathbf{e}_j - \mathbf{e}_i||}$$

## Comparison with RNA Velocity

| Aspect | CellODE | RNA Velocity (scVelo) |
|--------|---------|----------------------|
| Input | Gene expression only | Spliced/unspliced counts |
| Model | Neural ODE | Steady-state/dynamic model |
| Time inference | Joint with dynamics | Separate |
| R package | Native R | Python (reticulate needed) |

## Best Practices

### 1. Neighbor Selection

```{r best-practice-neigh, eval=FALSE}
# More neighbors = smoother but less detailed
T_smooth <- cosine_similarity(zs, vf, n_neigh = 30)

# Fewer neighbors = more detail but noisier
T_detail <- cosine_similarity(zs, vf, n_neigh = 10)
```

### 2. Visualization Density

```{r best-practice-viz, eval=FALSE}
# Publication figure (fewer arrows)
plot_vector_field(srt, arrow_density = 0.3)

# Exploration (more arrows)
plot_vector_field(srt, arrow_density = 1.0)
```

### 3. Self-Transition

```{r best-practice-self, eval=FALSE}
# Include self-transition for smoother results
V_with_self <- vector_field_embedding(T_mat, E, self_transition = TRUE)
```

## Summary

CellODE provides a complete workflow for vector field analysis:

| Function | Purpose |
|----------|---------|
| `cosine_similarity()` | Compute transition probabilities |
| `vector_field_embedding()` | Project to embedding space |
| `vector_field_embedding_grid()` | Grid-based smoothing |
| `plot_vector_field()` | Visualize vector field |
| `plot_pseudotime()` | Visualize pseudotime with arrows |

## Session Info

```{r session}
sessionInfo()
```
