corrplot one column multiple groups single plot - r

I would like a corrplot, where I only have the first column. I got that solution from here:
Corrplot with only one variable on x axis
library(corrplot)
corrplot(cor(iris[,1:4])[1:4,1, drop=FALSE], cl.pos='n')
but I would like the first column to repeat WITHIN THE SAME PLOT by group:
I am not married to using corrplot but need some similar solution. Thanks for any and all help.

Here is a hacky way to do it without an additional package:
library(corrplot)
Dat<-cor(iris[,1:4])[1:4,1, drop=FALSE]
PlotDat<-cbind(Dat,Dat,Dat)
corrplot(PlotDat, cl.pos='n')

If you want complete control over your plot, you could do something like this using ggplot2
library(tidyverse)
as.data.frame(cor(iris[1:4])[,rep(1, 3)]) %>%
setNames(1:3) %>%
rownames_to_column() %>%
pivot_longer(-rowname) %>%
mutate(rowname = factor(rowname, rev(unique(rowname)))) %>%
ggplot(aes(name, rowname)) +
geom_tile(fill = 'white', color = 'black') +
geom_point(aes(size = abs(value), color = value)) +
coord_equal() +
scale_x_discrete(NULL, labels = rep('Sepal.Length', 3), expand = c(0, 0),
position = 'top') +
scale_y_discrete(NULL, expand = c(0, 0)) +
scale_color_gradientn(colors = c('red3', 'red', 'white', '#4080ce', '#063062'),
limits = c(-1, 1), guide = 'none') +
scale_size_continuous(limits = c(0, 1), range = c(0, 20), guide = 'none') +
theme(axis.text.x = element_text(angle = 90),
plot.margin = margin(20, 20, 20, 20))

Related

How to move dots closer together in circular dot plot in R using ggplot?

I have this code below which creates a figure that is near perfect for what I need, except I need to know how to adjust the dot distances from each other. Changing dot size will not help because I have some data sets that will have over a 10000 points (some type of clustering could work too). The dots end up covering the entire circle because the dots have so much space between them.
Any help is appreciated!
library(tidyverse)
ACT34_radarplot_input %>%
hist(breaks = seq(0, 24, 0.2), plot = FALSE) %>%
`[`(c(2, 4)) %>%
as_tibble() %>%
group_by(mids) %>%
summarize(y = -seq(counts), .groups = "drop") %>%
filter(y < 0) %>%
ggplot(aes(mids, y)) +
geom_point(col = "red2", size = 3) +
geom_hline(yintercept = 0) +
scale_x_continuous(breaks = c(0:24), limits = c(0, 24)) +
ylim(c(-20, 0)) +
coord_polar() +
ggtitle("Act 34 Significant Genes Phases") +
theme_void() +
theme(axis.text.x = element_text(size = 16),
plot.title = element_text(size = 20, hjust = 0.5))
Here is the figure as is.

Change ggplot bar chart fill colors

With this data:
df <- data.frame(value =c(20, 50, 90),
group = c(1, 2,3))
I can get a bar chart:
df %>% ggplot(aes(x = group, y = value, fill = value)) +
geom_col() +
coord_flip()+
scale_fill_viridis_c(option = "C") +
theme(legend.position = "none")
But I would like to have the colors of those bars to vary according to their corresponding values in value.
I have managed to change them using geom_raster:
ggplot() +
geom_raster(aes(x = c(0:20), y = .9, fill = c(0:20)),
interpolate = TRUE) +
geom_raster(aes(x = c(0:50), y = 2, fill = c(0:50)),
interpolate = TRUE) +
geom_raster(aes(x = c(0:90), y = 3.1, fill = c(0:90)),
interpolate = TRUE) +
scale_fill_viridis_c(option = "C") +
theme(legend.position = "none")
This approach is not efficient when I have many groups in real data. Any suggestions to get it done more efficiently would be appreciated.
I found the accepted answer to a previous similar question, but "These numbers needs to be adjusted depending on the number of x values and range of y". I was looking for an approach that I do not have to adjust numbers based on data. David Gibson's answer fits my purpose.
It does not look like this is supported natively in ggplot. I was able to get something close by adding additional rows, ranging from 0 to value) to the data. Then use geom_tile and separating the tiles by specifying width.
library(tidyverse)
df <- data.frame(value = c(20, 50, 90),
group = c(1, 2, 3))
df_expanded <- df %>%
rowwise() %>%
summarise(group = group,
value = list(0:value)) %>%
unnest(cols = value)
df_expanded %>%
ggplot() +
geom_tile(aes(
x = group,
y = value,
fill = value,
width = 0.9
)) +
coord_flip() +
scale_fill_viridis_c(option = "C") +
theme(legend.position = "none")
If this is too pixilated you can increase the number of rows generated by replacing list(0:value) with seq(0, value, by = 0.1).
This is a real hack using ggforce. This package has a geom that can take color gradients but it is for a line segment. I've just increased the size to make the line segment look like a bar. I made all the bars the same length to get the correct gradient, then covered a portion of each bar over with the same color as the background color to make them appear to be the correct length. Had to hide the grid lines, however. :-)
df %>%
ggplot() +
geom_link(aes(x = 0, xend = max(value), y = group, yend = group, color = stat(index)), size = 30) +
geom_link(aes(x = value, xend = max(value), y = group, yend = group), color = "grey", size = 31) +
scale_color_viridis_c(option = "C") +
theme(legend.position = "none", panel.background = element_rect(fill = "grey"),
panel.grid = element_blank()) +
ylim(0.5, max(df$group)+0.5 )

Plotting two way bar chart using ggplot2

I have the following randomly created data:
t<- matrix(sample.int(100,size=20,replace=TRUE),nrow=12,ncol=20)
a = list()
b = list()
for (x in (1:20) ) b[[x]] <- paste0("X_", x)
for (x in (1:12) ) a[[x]] <- paste0("X", x)
row.names(t) <- rbind(a)
colnames(t) <- rbind(b)
t <- as.data.frame(t)
Here t is a hypothetical two way table of frequencies, I am trying to plot a graph like the one given here using ggplot2
I am not sure how can I make t in such a way that it can be used in ggplot2 code given in the link above. Also, I appreciate if you can provide suggestions on how to visualize a larger two way table, for instance, if dimension of t grows to something 30 x 50.
Here's one approach:
EDIT to show values underneath:
t %>%
rownames_to_column() %>%
pivot_longer(-rowname) %>%
mutate(across(rowname:name, fct_inorder)) %>%
ggplot(aes(x = 1, y = value)) +
geom_col() +
geom_text(aes(x = 1, y = 0, label = value), vjust = 1.1, size = 2.5) +
scale_x_continuous(breaks = NULL) +
scale_y_continuous(breaks = NULL) +
facet_grid(rowname~name) +
coord_cartesian(clip = "off")
Here is a modification of Jon Springs code with some "layout" tweaking:
library(tidyverse)
df %>%
rownames_to_column() %>%
pivot_longer(-rowname) %>%
mutate(across(rowname:name, fct_inorder)) %>%
ggplot(aes(x = 1, y = value, fill=value)) +
geom_col(width = 0.5) +
geom_text(aes(x = 1, y = 0, label = value), vjust = 1.1, size = 2.5) +
scale_x_continuous(breaks = NULL) +
scale_y_continuous(breaks = NULL) +
facet_grid(rowname~name, switch = "both") +
coord_cartesian(clip = "off") +
theme_void() +
theme(strip.background = element_blank(),
strip.text.y.left = element_text(angle = 0),
panel.spacing = unit(1, "lines"),
strip.placement = "outside",
strip.switch.pad.grid = unit(0.2, "in"))+
guides(fill="none")

How to create such a figure using ggplot2 in R?

I have a matrix with many zero elements. The column names are labeled on the horizontal axis. I'd like to show explictly the nonzero elements as the bias from the vertical line for each column.
So how should construct a figure such as the example using ggplot2?
An example data can be generated as follow:
set.seed(2018)
N <- 5
p <- 40
dat <- matrix(0.0, nrow=p, ncol=N)
dat[2:7, 1] <- 4*rnorm(6)
dat[4:12, 2] <- 2.6*rnorm(9)
dat[25:33, 3] <- 2.1*rnorm(9)
dat[19:26, 4] <- 3.3*rnorm(8)
dat[33:38, 5] <- 2.9*rnorm(6)
colnames(dat) <- letters[1:5]
print(dat)
Here is another option using facet_wrap and geom_col with theme_minimal.
library(tidyverse)
dat %>%
as.data.frame() %>%
rowid_to_column("row") %>%
gather(key, value, -row) %>%
ggplot(aes(x = row, y = value, fill = key)) +
geom_col() +
facet_wrap(~ key, ncol = ncol(dat)) +
coord_flip() +
theme_minimal()
To further increase the aesthetic similarity to the plot in your original post we can
move the facet strips to the bottom,
rotate strip labels,
add "zero lines" in matching colours,
remove the fill legend, and
get rid of the x & y axis ticks/labels/title.
library(tidyverse)
dat %>%
as.data.frame() %>%
rowid_to_column("row") %>%
gather(key, value, -row) %>%
ggplot(aes(x = row, y = value, fill = key)) +
geom_col() +
geom_hline(data = dat %>%
as.data.frame() %>%
gather(key, value) %>%
count(key) %>%
mutate(y = 0),
aes(yintercept = y, colour = key), show.legend = F) +
facet_wrap(~ key, ncol = ncol(dat), strip.position = "bottom") +
coord_flip() +
guides(fill = FALSE) +
theme_minimal() +
theme(
strip.text.x = element_text(angle = 45),
axis.title = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank())
It would be much easier if you can provide some sample data. Thus I needed to create them and there is no guarantee that this will work for your purpose.
set.seed(123)
# creating some random sample data
df <- data.frame(id = rep(1:100, each = 3),
x = rnorm(300),
group = rep(letters[1:3], each = 100),
bias = sample(0:1, 300, replace = T, prob = c(0.7, 0.3)))
# introducing bias
df$bias <- df$bias*rnorm(nrow(df))
# calculate lower/upper bias for errorbar
df$biaslow <- apply(data.frame(df$bias), 1, function(x){min(0, x)})
df$biasupp <- apply(data.frame(df$bias), 1, function(x){max(0, x)})
Then I used kind of hack to be able to print groups in sufficient distance to make them not overlapped. Based on group I shifted bias variable and also lower and upper bias.
# I want to print groups in sufficient distance
df$bias <- as.numeric(df$group)*5 + df$bias
df$biaslow <- as.numeric(df$group)*5 + df$biaslow
df$biasupp <- as.numeric(df$group)*5 + df$biasupp
And now it is possible to plot it:
library(ggplot2)
ggplot(df, aes(x = x, col = group)) +
geom_errorbar(aes(ymin = biaslow, ymax = biasupp), width = 0) +
coord_flip() +
geom_hline(aes(yintercept = 5, col = "a")) +
geom_hline(aes(yintercept = 10, col = "b")) +
geom_hline(aes(yintercept = 15, col = "c")) +
theme(legend.position = "none") +
scale_y_continuous(breaks = c(5, 10, 15), labels = letters[1:3])
EDIT:
To incorporate special design you can add
theme_bw() +
theme(axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
axis.title.y = element_blank(),
axis.text.x = element_text(angle = 45, vjust = 0.5, hjust = 1),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank())
to your plot.
EDIT2:
To incorporate several horizontal lines, you can create different dataset:
df2 <- data.frame(int = unique(as.numeric(df$group)*5),
gr = levels(df$group))
And use
geom_hline(data = df2, aes(yintercept = int, col = gr))
instead of copy/pasting geom_hline for each group level.

heatmap in ggplot, different color for each group

I am trying to produce a heatmap in ggplot. I want each group to have different color gradient, but don't know how to do that. My current code looks like this:
## dummy data -----------------------------------------------------------------------------
data <- data.frame(
group = sample(c("Direct Patient Care", "Indirect Patient Care", "Education", "Rounds", "Handoff", "Misce"), 30, replace = T),
pct = rnorm(30, mean = 50, sd = 8)
)
## generate group id
data <- data %>%
group_by(group) %>%
mutate(id = row_number())
data$grpid <- with(data, ifelse(group == "Direct Patient Care", 1, ifelse(group == "Indirect Patient Care", 2,
ifelse(group == "Education", 3,
ifelse(group == "Rounds", 4,
ifelse(group == "Handoff", 5,6 ))))))
## draw graph ------------------------------------------------------------------------------
library(ggplot2)
p <- ggplot(data, aes(x=id, y=group, fill = pct)) +
theme(panel.background = element_rect(fill = "white", colour = "grey50"), aspect.ratio = 0.4) +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank()
)+
# guides(fill = guide_legend("Time, %")) +
geom_tile() +
scale_x_continuous (name = " ", breaks = seq(1, 8, by = 1)) +
scale_y_discrete(name = " ") +
theme(axis.text.x = element_text(angle = 0,hjust = 1,vjust = 1), plot.title = element_text(hjust = 0.5) ) +
ggtitle("Heatmap of time spent doing activities across 194 shifts")
p + scale_fill_gradient2(low = "white", high = "red", limits = c(0, 80), breaks = c(0, 10, 20, 30, 40, 50, 60, 70), guide = guide_legend("Time, %")) ## change the color theme ##
And the resulting figure looks like this:
How can I change the color theme for each group, like red for 'Rounds', blue for 'Misce', green for 'Handoff' etc...
Many thanks!
You can do this by creating your own rescaled value in your data and then slightly "hacking" the alpha aesthetic combined with the fill aesthetic:
library(tidyverse)
data %>%
group_by(group) %>%
mutate(rescale = scales::rescale(pct)) %>%
ggplot(., aes(x = factor(id), y = group)) +
geom_tile(aes(alpha = rescale, fill = group), color = "white") +
scale_alpha(range = c(0.1, 1))
First we create a new column called rescale which rescales the pct from 0 to 1 then you force the scale_alpha(range = c(0, 1)) [note, in this case I used c(0.1, 1) so that you can still "see" the zero points.
Finally, you probably want to remove the guides:
data %>%
group_by(group) %>%
mutate(rescale = scales::rescale(pct)) %>%
ggplot(., aes(x = factor(id), y = group)) +
geom_tile(aes(alpha = rescale, fill = group), color = "white") +
scale_alpha(range = c(0.1, 1)) +
theme(legend.position = "none")
N.B. by using aes(x = factor(id)... you can get around manually setting your x-axis since in this case it appears you want to treat it as a factor not a numeric scale.
Finally, if you really want to get fancy, you could double-encode the axis.text.y colors to that of the levels of your factor (i.e., data$group) variable:
data %>%
group_by(group) %>%
mutate(rescale = scales::rescale(pct)) %>%
ggplot(., aes(x = factor(id), y = group)) +
geom_tile(aes(alpha = rescale, fill = group), color = "white") +
scale_alpha(range = c(0.1, 1)) +
theme(legend.position = "none",
axis.text.y = element_text(color = scales::hue_pal()(length(levels(data$group)))),
axis.ticks = element_blank()) +
labs(x = "", y = "")

Resources