Skip to content

Commit

Permalink
update vis
Browse files Browse the repository at this point in the history
  • Loading branch information
Reed Nelson committed Oct 6, 2024
1 parent 7c27bf0 commit 0712960
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 114 deletions.
14 changes: 10 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# MiNAA: Microbiome Network Alignment Algorithm

<img src="logo.png" style="width:40%;" align=right>
<img src="img/logo.png" style="width:40%;" align=right>

[![GitHub Releases](https://img.shields.io/github/v/release/solislemuslab/minaa?display_name=tag)](https://github.com/solislemuslab/minaa/releases) [![GitHub license](https://img.shields.io/github/license/solislemuslab/minaa)](https://github.com/solislemuslab/minaa/blob/main/LICENSE) [![GitHub Issues](https://img.shields.io/github/issues/solislemuslab/minaa)](https://github.com/solislemuslab/minaa/issues) ![ ](https://img.shields.io/github/languages/code-size/solislemuslab/minaa) [![status](https://joss.theoj.org/papers/b4d9f26021065b1759d50413f60aa9c3/status.svg)](https://joss.theoj.org/papers/b4d9f26021065b1759d50413f60aa9c3)
[![GitHub Releases](https://img.shields.io/github/v/release/solislemuslab/minaa?display_name=tag)](https://github.com/solislemuslab/minaa/releases) [![GitHub license](https://img.shields.io/github/license/solislemuslab/minaa?color=yellow)](https://github.com/solislemuslab/minaa/blob/main/LICENSE) [![GitHub Issues](https://img.shields.io/github/issues/solislemuslab/minaa)](https://github.com/solislemuslab/minaa/issues) ![ ](https://img.shields.io/github/languages/code-size/solislemuslab/minaa?color=white) [![status](https://joss.theoj.org/papers/b4d9f26021065b1759d50413f60aa9c3/status.svg)](https://joss.theoj.org/papers/b4d9f26021065b1759d50413f60aa9c3)

## Description

Expand Down Expand Up @@ -67,7 +67,7 @@ This utility has the form `./minaa.exe <G> <H> [-B=bio] [-a=alpha] [-b=beta]`.
- **-c**: conserved subgraphs; whether or not to output a list of the conserved subgraphs in the alignment between G and H.
- Require: none.
- Default: this list is not calculated or returned.
- Note: We define a conserved subgraph as a connected subgraph of G whose nodes are aligned to a connected subgraph of H.
- Note: We define a conserved subgraph as a connected subgraph of G whose nodes are aligned to a connected subgraph of H. See the Examples section for a visual.

#### Uncommon

Expand Down Expand Up @@ -109,6 +109,12 @@ This utility has the form `./minaa.exe <G> <H> [-B=bio] [-a=alpha] [-b=beta]`.

### Examples

<img src="img/conserved_subgraph.png" style="width:60%;" align=center>

On the left are adjacency matrices for simple networks G and H, and an imagined **alignment matrix** as returned by MiNAA. On the right is a visual depiction of G overlaying H, and the connected purple graph is what we call a **conserved subgraph** in the alignment of G and H. We color a node purple if that node in G is aligned to a node in H, and we color an edge purple if a pair of adjacent nodes in G are also adjacent in the nodes they're aligned to in H. Note that the blue edge, red edge, and red node `e` are not considered part of this conserved subgraph.

#### Example Execution

Examples of MiNAA's usage with real data and in-depth explanations can be found in the `examples/` directory.

## Simulations in the Manuscript
Expand All @@ -121,7 +127,7 @@ Users interested in expanding functionalities in MiNAA are welcome to do so. Iss

## License

MiNAA is licensed under the [MIT](https://opensource.org/licenses/MIT) license. &copy; SolisLemus lab (2024).
MiNAA is licensed under the [MIT](https://opensource.org/licenses/MIT) license. &copy; Solis-Lemus Lab (2024).

## Citation

Expand Down
8 changes: 3 additions & 5 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,12 @@ plot_alignment(
h_filepath = "examples/h.csv",
alignment_filepath = "examples/g-h/alignment_matrix.csv",
output_filepath = "examples/g-h/plot.png",
th_align = 0.2,
zero_degree = 0,
vertex_label_value = 0.1,
size_aligned = 5
st = 0.5,
hide_singletons = TRUE
)
```

This is an example execution in R of the alignment visualization script `plot_alignment.R`.
This is an example execution in R of the alignment visualization script `plot_alignment.R`. The resulting `plot.png` is in `examples/g-h/`.

## Attributions

Expand Down
Binary file modified examples/g-h/plot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/conserved_subgraph.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
249 changes: 144 additions & 105 deletions plot_alignment.R
Original file line number Diff line number Diff line change
@@ -1,106 +1,145 @@
plot_alignment <- function(g_filepath, h_filepath, alignment_filepath, output_filepath, th_align, zero_degree, vertex_label_value, size_aligned) {

# Load adjacency matrices and alignment matrix
adj_G <- as.matrix(read.csv(g_filepath, header = TRUE, row.names = 1, check.names = FALSE))
adj_H <- as.matrix(read.csv(h_filepath, header = TRUE, row.names = 1, check.names = FALSE))
alignment_GH <- as.matrix(read.csv(alignment_filepath, header = TRUE, row.names = 1, check.names = FALSE))

g_size <- nrow(adj_G)
h_size <- nrow(adj_H)
adj_G <- adj_G[1:g_size, 1:g_size]
adj_H <- adj_H[1:h_size, 1:h_size]
alignment_GH <- alignment_GH[1:g_size, 1:h_size]

# Create graph objects with unique vertex names
graph_G <- graph_from_adjacency_matrix(adj_G, mode = "undirected")
V(graph_G)$name <- rownames(adj_G)

graph_H <- graph_from_adjacency_matrix(adj_H, mode = "undirected")
V(graph_H)$name <- rownames(adj_H)

# Identify aligned nodes
alignment_indices <- which(alignment_GH >= th_align, arr.ind = TRUE)
aligned_nodes_G <- V(graph_G)$name[alignment_indices[, 1]]
aligned_nodes_H <- V(graph_H)$name[alignment_indices[, 2]]

# Optionally remove nodes with degree 0, except aligned nodes
zero_deg_nodes_G <- V(graph_G)[degree(graph_G) < zero_degree & !(V(graph_G)$name %in% aligned_nodes_G)]
zero_deg_nodes_H <- V(graph_H)[degree(graph_H) < zero_degree & !(V(graph_H)$name %in% aligned_nodes_H)]
graph_G <- delete.vertices(graph_G, zero_deg_nodes_G)
graph_H <- delete.vertices(graph_H, zero_deg_nodes_H)

# Re-calculate the aligned nodes after potential removal
aligned_indices_G <- match(aligned_nodes_G, V(graph_G)$name)
aligned_indices_H <- match(aligned_nodes_H, V(graph_H)$name)

# Filter out NA values from aligned indices
valid_indices <- which(!is.na(aligned_indices_G) & !is.na(aligned_indices_H))
aligned_indices_G <- aligned_indices_G[valid_indices]
aligned_indices_H <- aligned_indices_H[valid_indices]

# Create a combined graph for alignment visualization
combined_graph <- graph.disjoint.union(graph_G, graph_H)

# Define layout for combined graph with circular layout
layout_G <- layout_in_circle(graph_G)
layout_H <- layout_in_circle(graph_H)

png(output_filepath, width = 1600, height = 1200, res = 120)

# Adjust the layout to place aligned nodes directly opposite each other
adjust_opposite_positions <- function(layout_G, layout_H, indices_G, indices_H) {
num_nodes <- length(indices_G)
angle_step <- pi / (num_nodes + 1)
start_angle <- pi / 2

for (i in seq_along(indices_G)) {
angle <- start_angle - (i * angle_step)
layout_G[indices_G[i], ] <- c(cos(angle), sin(angle))
layout_H[indices_H[i], ] <- c(-cos(angle), sin(angle))
plot_alignment <- function(
g_filepath,
h_filepath,
alignment_filepath,
output_filepath,
st = 0,
hide_singletons = FALSE
) {
# # Load necessary libraries
# required_packages <- c("igraph", "ggraph", "ggplot2", "readr", "dplyr")
# installed_packages <- rownames(installed.packages())
# for (pkg in required_packages) {
# if (!pkg %in% installed_packages) {
# install.packages(pkg, dependencies = TRUE)
# }
# }

library(igraph)
library(ggraph)
library(ggplot2)
library(readr)
library(dplyr)

# Helper function to read adjacency matrix
read_adjacency <- function(filepath) {
df <- read_csv(filepath, show_col_types = FALSE)
mat <- as.matrix(df[, -1])
rownames(mat) <- df[[1]]
return(mat)
}
return(list(layout_G, layout_H))
}

layouts <- adjust_opposite_positions(layout_G, layout_H, aligned_indices_G, aligned_indices_H)
layout_G <- layouts[[1]]
layout_H <- layouts[[2]]

# Reduce the separation distance between G and H networks
layout_G <- layout_G - cbind(rep(2, nrow(layout_G)), rep(0, nrow(layout_G)))
layout_H <- layout_H + cbind(rep(2, nrow(layout_H)), rep(0, nrow(layout_H)))

# Combine layouts
layout_combined <- rbind(layout_G, layout_H)

# Add edges based on alignment matrix GH
for (i in seq_along(aligned_indices_G)) {
combined_graph <- add_edges(combined_graph, c(aligned_indices_G[i], aligned_indices_H[i] + vcount(graph_G)))
}

# Define colors for vertices and edges
vertex_colors <- c(rep("lightblue", vcount(graph_G)), rep("lightgreen", vcount(graph_H)))
vertex_colors[aligned_indices_G] <- "dodgerblue"
vertex_colors[aligned_indices_H + vcount(graph_G)] <- "green"
edge_colors <- c(rep("black", ecount(graph_G) + ecount(graph_H)), rep("purple", length(aligned_indices_G)))

# Define sizes and label sizes for vertices
vertex_sizes <- rep(1, vcount(combined_graph))
vertex_sizes[c(aligned_indices_G, aligned_indices_H + vcount(graph_G))] <- size_aligned
vertex_label_sizes <- rep(vertex_label_value, vcount(combined_graph))
vertex_label_sizes[c(aligned_indices_G, aligned_indices_H + vcount(graph_G))] <- 0.8

# Plot the combined graph with alignment edges
plot(combined_graph,
layout = layout_combined,
vertex.label = V(combined_graph)$name, # Add vertex labels
vertex.size = vertex_sizes, # Adjust vertex size for better visualization
vertex.label.cex = vertex_label_sizes, # Adjust label size for better readability
vertex.color = vertex_colors,
edge.color = edge_colors,
edge.width = c(rep(1, ecount(graph_G) + ecount(graph_H)), rep(2, length(aligned_indices_G))),
main = "Result of MiNAA",
asp = 0 # Set aspect ratio to ensure circular layout
)

dev.off()
}

# Read adjacency matrices
g_mat <- read_adjacency(g_filepath)
h_mat <- read_adjacency(h_filepath)

# Create igraph objects (assuming undirected graphs; adjust 'mode' if needed)
g_graph <- graph_from_adjacency_matrix(g_mat, mode = "undirected", diag = FALSE)
h_graph <- graph_from_adjacency_matrix(h_mat, mode = "undirected", diag = FALSE)

# Read alignment matrix
alignment_df <- read_csv(alignment_filepath, show_col_types = FALSE)
alignment_mat <- as.matrix(alignment_df[, -1])
rownames(alignment_mat) <- alignment_df[[1]]

# Extract alignment pairs with similarity > the similarity threshold
alignment_pairs <- which(alignment_mat > st, arr.ind = TRUE)
align_df <- data.frame(
g_node = rownames(alignment_mat)[alignment_pairs[, 1]],
h_node = colnames(alignment_mat)[alignment_pairs[, 2]],
similarity = alignment_mat[alignment_pairs]
)

if (hide_singletons) {
# Remove nodes in G and H with degree 0
deg_g <- degree(g_graph)
non_single_g <- names(deg_g[deg_g > 0])
g_graph <- induced_subgraph(g_graph, vids = non_single_g)

deg_h <- degree(h_graph)
non_single_h <- names(deg_h[deg_h > 0])
h_graph <- induced_subgraph(h_graph, vids = non_single_h)

# Update alignment_df to include only existing nodes after subsetting
align_df <- align_df %>%
filter(g_node %in% V(g_graph)$name & h_node %in% V(h_graph)$name)
}

# Rename nodes to ensure uniqueness
V(g_graph)$name <- paste0("G_", V(g_graph)$name)
V(h_graph)$name <- paste0("H_", V(h_graph)$name)

combined_graph <- disjoint_union(g_graph, h_graph)

# Prepare alignment edges
if (nrow(align_df) > 0) {
align_edges <- align_df %>%
mutate(
from = paste0("G_", g_node),
to = paste0("H_", h_node)
)
} else {
align_edges <- data.frame(from = character(0), to = character(0), similarity = numeric(0))
}

# Create a layout with G on the left and H on the right
set.seed(123) # For reproducibility
layout_g <- layout_with_fr(g_graph)
layout_h <- layout_with_fr(h_graph)

# Shift H layout to the right of G
shift_x <- max(layout_g[, 1]) - min(layout_h[, 1]) + 5
layout_h[, 1] <- layout_h[, 1] + shift_x

# Combine layouts
combined_layout <- rbind(layout_g, layout_h)
V(combined_graph)$x <- combined_layout[, 1]
V(combined_graph)$y <- combined_layout[, 2]

# Prepare data for alignment edges
if (nrow(align_edges) > 0) {
align_coords <- align_edges %>%
mutate(
from_x = V(combined_graph)$x[match(from, V(combined_graph)$name)],
from_y = V(combined_graph)$y[match(from, V(combined_graph)$name)],
to_x = V(combined_graph)$x[match(to, V(combined_graph)$name)],
to_y = V(combined_graph)$y[match(to, V(combined_graph)$name)]
)
}

# Plot #

# Adjust the plot size based on the number of nodes
num_nodes <- vcount(combined_graph)
plot_width <- max(2000, 100 + 20 * num_nodes)
plot_height <- max(1000, 100 + 10 * num_nodes)

png(filename = output_filepath, width = plot_width, height = plot_height, res = 150)

p <- ggraph(combined_graph, layout = "manual", x = V(combined_graph)$x, y = V(combined_graph)$y) +
# Internal edges within G and H
geom_edge_link(aes(alpha = 0.5), color = "grey", linewidth = 0.5) +
# G nodes in red, H in blue
geom_node_point(aes(color = ifelse(startsWith(name, "G_"), "G", "H")), size = 3) +
# Node labels without the prefix
geom_node_text(aes(label = gsub("^[GH]_", "", name)), repel = TRUE, size = 3)
# Color mapping
scale_color_manual(values = c("G" = "red", "H" = "blue")) +
theme_void() +
theme(legend.position = "none")

if (nrow(align_edges) > 0) {
# Add alignment edges
p <- p +
geom_segment(
data = align_coords,
aes(x = from_x, y = from_y, xend = to_x, yend = to_y),
color = "purple", linewidth = 0.5, alpha = 0.6
)
}

print(p)
dev.off()

message("Plot saved to ", output_filepath)
}

0 comments on commit 0712960

Please sign in to comment.