thomasp85 / ggforce

Accelerating ggplot2
https://ggforce.data-imaginist.com
Other
916 stars 106 forks source link

Use `facet_matrix`'s labels in `aes()` #255

Closed mattansb closed 2 years ago

mattansb commented 2 years ago

I'd like the have shapes vary by the rows of a facet_matrix, is this possible? How does one access the x/y panel ID?

library(ggplot2)
library(ggforce)

ggplot(mtcars) + 
  geom_point(aes(.panel_x, .panel_y)) + 
  facet_matrix(vars(mpg, cyl), vars(am, hp))

# How to have aes(shape = (.panel_x_var == "hp))?
thomasp85 commented 2 years ago

There is a secret PANEL variable added to all data in R... while it is honestly not meant to be used like this it is there:

ggplot(mtcars) + 
    geom_point(aes(.panel_x, .panel_y, shape = factor(PANEL))) + 
    facet_matrix(vars(mpg, cyl), vars(am, hp))

thomasp85 commented 2 years ago

With some mathematics you should be able to target each row

mattansb commented 2 years ago

Oh that is some nice magic.

If anyone ever comes looking here...:

library(ggplot2)
library(ggforce)

p <- ggplot(mtcars) + 
  geom_point(aes(.panel_x, .panel_y)) + 
  facet_matrix(vars(mpg, am, cyl, carb), vars(am, cyl, hp))

factor_to_row <- function(f, nrow) {
  ncol <- max(as.numeric(f)) / nrow
  factor((as.numeric(f) - 1) %/% ncol)
}

factor_to_col <- function(f, ncol) {
  factor((as.numeric(f) - 1) %% ncol)
}

p + aes(shape = factor_to_row(PANEL, 4))
#> Warning in rows == cols: longer object length is not a multiple of shorter
#> object length


p + aes(shape = factor_to_col(PANEL, 3))
#> Warning in rows == cols: longer object length is not a multiple of shorter
#> object length

Created on 2022-08-31 by the reprex package (v2.0.1)

Pancreas-Pratik commented 1 month ago

There is a secret PANEL variable added to all data in R... while it is honestly not meant to be used like this it is there:

ggplot(mtcars) + 
    geom_point(aes(.panel_x, .panel_y, shape = factor(PANEL))) + 
    facet_matrix(vars(mpg, cyl), vars(am, hp))

Yes!! This is everything I needed! I've been struggling how to color specific plots within the plot grid conditionally. This will help me do this!

Please do not ever remove this @thomasp85 🙏🏾 I've been struggling for hours now, and this (factor(PANEL)) was the key I needed!


EDIT: If anyone comes looking for this.... this is how I accomplished my use-case of coloring specific plots' points and trend lines different colors:

Summary I created a color matrix that matched the ordering of my ggforce facet matrix with the coloring cut-offs I wanted, flattened the color matrix to a vector appropriately to match the order of the coloring sequence, and then with color = factor(PANEL) set within the geom_point(aes()), and geom_smooth(aes()). I applied the output flattened color vector like so: scale_color_manual(values = color_vector). This is how it looks all together with my simulated data:

Code: Generate simulated data


# Step 1: Generate Simulated Data for 30 genes and 30 cells
set.seed(42)
gene_data <- matrix(rnorm(900), nrow = 30)
gene_data <- as.data.frame(gene_data)
colnames(gene_data) <- paste("Gene", 1:30, sep = "_")
rownames(gene_data) <- paste("Cell", 1:30, sep = "_")

# Step 2: Make some genes have all zeros
set.seed(42)
genes_to_zero <- sample(1:ncol(gene_data), 3)
gene_data[, genes_to_zero] <- 0

# Step 3: Compute the Full Correlation Matrix
correlation_matrix <- cor(gene_data)

correlation_matrix <- correlation_matrix[rowSums(!is.na(correlation_matrix)) > 1, , drop = FALSE]

correlation_matrix <- correlation_matrix[, colSums(!is.na(correlation_matrix)) > 0, drop = FALSE]
subset_matrix <- correlation_matrix 

set.seed(42)
rows_to_na <- sample(1:nrow(subset_matrix), 4)
cols_to_na <- sample(1:ncol(subset_matrix), 7)
subset_matrix[rows_to_na, ] <- NA
subset_matrix[, cols_to_na] <- NA

subset_matrix <- subset_matrix[rowSums(!is.na(subset_matrix)) > 0, , drop = FALSE]

subset_matrix <- subset_matrix[, colSums(!is.na(subset_matrix)) > 0, drop = FALSE]

subset_matrix[!(subset_matrix >= 0.30 | subset_matrix <= -0.30)] <- NA

subset_matrix <- subset_matrix[rowSums(!is.na(subset_matrix)) > 0, , drop = FALSE]

subset_matrix <- subset_matrix[, colSums(!is.na(subset_matrix)) > 0, drop = FALSE]

############

count_matrix_combined <- gene_data
cor_matrix_combined <- subset_matrix

Mapping colors to plots on the facet_matrix

# Step 1: Generate the color matrix based on the correlation values
color_matrix <- matrix("grey", nrow = nrow(cor_matrix_combined), ncol = ncol(cor_matrix_combined))
color_matrix[cor_matrix_combined > 0] <- "red"
color_matrix[cor_matrix_combined < 0] <- "blue"
color_matrix[is.na(cor_matrix_combined)] <- "grey"

# Step 2: Flatten the color matrix into a vector that matches the PANEL order
color_vector <- as.vector(t(color_matrix))  # Use `t()` to transpose so it matches the PANEL sequence

# Step 3: Generate scatter plots using facet_matrix with color mapping
scatter_plot_matrix_ggforce <- ggplot(count_matrix_combined) +
  geom_point(aes(x = .panel_x, y = .panel_y, color = factor(PANEL)), alpha = 0.6) +
  geom_smooth(aes(x = .panel_x, y = .panel_y, color = factor(PANEL)), method = "lm", se = FALSE) +
  facet_matrix(
    rows = vars(rownames(cor_matrix_combined)), 
    cols = vars(colnames(cor_matrix_combined))
  ) +
  scale_color_manual(values = color_vector) +  # Apply the color vector
  theme(
    strip.text = element_text(size = 20, face = "italic"), 
    axis.text = element_text(size = rel(1.25))
  ) + theme(legend.position="none")

Output:

Screenshot 2024-07-31 at 9 58 33 PM