I have the following data.table:
require(data.table)
require(ggplot2)
set.seed(1234)
dt = data.table(id = paste0('ID_', 1:2000),
group = rep(LETTERS[1:5], 400),
value = as.logical(rbinom(2000, 1, prob = 0.25)))
I would like to create a ggplot like below, where on the y-axis only the text labels, for which the variable value equals TRUE are drawn, without removing the other data. Additionally, it would be best, if the text labels won't overlap (if possible), hence using all the empty y-axis space.
# draws all categorical id values
ggplot(dt, aes(y = reorder(id, -value), x = group, fill = value)) +
geom_tile() +
theme_bw()
Update: For the first 100 cases:
dt1 <- dt %>%
mutate(ylabel = ifelse(value==TRUE, id, "")) %>%
slice(1:100)
ggplot(dt1, aes(y = reorder(id, -value), x = group, fill = value)) +
geom_tile() +
scale_y_discrete(
labels = dt1$ylabel
) +
theme_bw()
Related
I'm trying to replicate a plot drawn by graphpad in r
but I have a problem changing the y axis
here is an example data and my plot codes:
library(ggplot2)
data <- data.frame(names = rep(factor(LETTERS[1:3])),
values = c(0.001, 0.02 ,0.95),
group = rep("A",3))
ggplot(data,
aes(x = group,
y = values,
fill = names)) + geom_bar(stat = "identity", position='stack') +
scale_y_continuous(breaks = c(0.001,0.01,0.1,1), labels=c(0.001,0.01,0.1,1))
the result of my code is on top but I want to plot it like the image on the bottom.
You can convert the values to their logs, then add a constant that makes all the log values greater than 0. Then re-label the axis appropriately:
data2 <- data %>%
mutate(logvalues = log10(values) - min(log10(0.0001)))
ggplot(data2[order(-data2$logvalues),],
aes(x = group, y = logvalues, fill = names)) +
geom_col(position = 'identity') +
scale_y_continuous(breaks = 0:4, labels = ~ 10^(.x-4))
How can geom_text_repel() labels be made to span multiple facet_grid() panes? For instance, if there are many long labels that do not fit within the proper dimensions of each grid plot, the label should be positioned as if the facet_grid() were a single plot.
For example:
df <- data.frame(
x = rep(1:3, 5),
y = runif(15),
label = paste0("very long label ", 1:15),
group = do.call(c, lapply(paste0("group ", 1:5), function(x) rep(x, 3)))
)
library(ggplot2)
library(ggrepel)
ggplot(df, aes(x, y, label = label)) +
geom_point() +
facet_grid(cols = vars(group)) +
geom_text_repel()
If there is another way to group samples on the x-axis that would mimic a column-wise facet-grid, that's perfectly fine too. In my case, I need to group samples by a grouping variable (correspondingly labeled), and then within each group order them by a continuous variable.
Use clip = "off" from coord_cartesian:
library(ggplot2)
library(ggrepel)
ggplot(df, aes(x, y, label = label)) +
geom_point() +
facet_grid(cols = vars(group)) +
geom_text_repel() +
coord_cartesian(clip = "off")
If this is not enough, one other option is to use multilining with stringr::str_wrap:
library(stringr)
library(dplyr)
df %>%
mutate(label_wrapped = str_wrap(label, width = 20)) %>%
ggplot(aes(x, y, label = label_wrapped)) +
geom_point() +
facet_grid(cols = vars(group)) +
geom_text_repel() +
coord_cartesian(clip = 'off')
data
set.seed(2)
df <- data.frame(
x = rep(1:3, 5),
y = runif(15),
label = paste0("very very very long label ", 1:15),
group = do.call(c, lapply(paste0("group ", 1:5), function(x) rep(x, 3)))
)
I have a data frame ("Date", "A", "B"). I'm trying to use boxplot (by month) to analysis the data "A" for the row filtered by "B" and also for all the "A". I can only create two separate plots to do the boxplot for specific rows and for whole rows of data.
I tried two have 2 geom_boxplot under one ggplot(), but two boxplot just overlap with each other. Here is the code I used. Does anyone know how I can combime those two boxplot into one, so two boxplots will share same x axis, and each month in x axis will have two boxes.
ggplot() +
geom_boxplot(data = df %>% filter(B == 1),
aes(x = Month, y = A, group=Month, fill = "Chamber_no fire"), outlier.shape = T) +
geom_boxplot(data = df, aes(x = Month, y = A, group=Month, fill="Chamber"), outlier.shape = T) +
theme_bw() +
theme(panel.grid.major = element_blank()) +
scale_x_continuous(breaks=seq(2,12,1), minor_breaks = F) +
geom_hline(yintercept = 0, linetype="dotted")
ggsave("sate_meas_O3_NOx_5km_nofire.png", width = 6, height = 4, units = "in")
One approach to achieve your desired result is to
Bind the filtered dataset and the total dataset by row and add an identifier id for each dataset which could easily be done via dplyr::bind_rows.
Make a boxplot where you map id on the fill aesthetic and group by both id and Month using interaction
Set the legend labels via scale_fill_discrete
As you provided no data I make use of a random example data set:
set.seed(42)
df <- data.frame(
Month = sample(2:12, 100, rep = TRUE),
A = rnorm(100),
B = sample(1:2, 100, rep = TRUE)
)
library(ggplot2)
library(dplyr)
d <- bind_rows(list(b1 = df %>% filter(B == 1),
all = df), .id = "id")
ggplot(data = d, mapping = aes(x = Month, y = A, group=interaction(Month, id), fill = id)) +
geom_boxplot(outlier.shape = T, position = "dodge") +
scale_fill_discrete(labels = c(b1 = "Chamber_no fire", all = "Chamber")) +
theme_bw() +
theme(panel.grid.major = element_blank()) +
scale_x_continuous(breaks=seq(2,12,1), minor_breaks = F) +
geom_hline(yintercept = 0, linetype="dotted")
I have the following code
library(ggplot2)
library(dplyr)
# create data
time <- as.numeric(rep(seq(1,7),each=7)) # x Axis
value <- runif(49, 10, 100) # y Axis
group <- rep(LETTERS[1:7],times=7) # group, one shape per group
data <- data.frame(time, value, group)
# stacked area chart
ggplot(data, aes(x=time, y=value, fill=group)) +
geom_area()+
geom_text(data = data %>% filter(time == last(time)), aes(label = group,
x = time + 0.5,
y = value,
color = group)) +
guides(color = FALSE) + theme_bw() +
scale_x_continuous(breaks = scales::pretty_breaks(10))
Where i get
But i am aiming for link
Is there any solution for stacked area plot?
The question code is plotting the text labels in the value's of the last time, when in fact the areas are cumulative. And in reverse order.
Also, the following graph plots data created with the same code but with
set.seed(1234)
Then the data creation code is the same as in the question.
# stacked area chart
ggplot(data, aes(x=time, y=value, fill=group)) +
geom_area()+
geom_text(data = data %>%
filter(time == last(time)) %>%
mutate(value = cumsum(rev(value))),
aes(label = rev(group),
x = time + 0.5,
y = value,
color = rev(group))) +
guides(color = FALSE) + theme_bw() +
scale_x_continuous(breaks = scales::pretty_breaks(10))
Edit.
Following the discussion in the comments to this answer, I have decided to post code based on the comment by user Jake Kaupp.
ggplot(data, aes(x = time, y = value, fill = group)) +
geom_area()+
geom_text(data = data %>% filter(time == last(time)),
aes(x = time + 0.5, y = value,
label = rev(group), color = rev(group)),
position = position_stack(vjust = 0.5)) +
guides(color = FALSE) +
theme_bw() +
scale_x_continuous(breaks = scales::pretty_breaks(10))
You can use the text function to put text wherever you want. For example:
text(7.2, 350, "B", col="brown")
Here we go
time <- as.numeric(rep(seq(1,7),each=8)) # x Axis
value <- runif(56, 10, 100) # y Axis
group <- rep(LETTERS[1:8],times=7) # group, one shape per group
data <- data.frame(time, value, group)
round_df <- function(x, digits) {
# round all numeric variables
# x: data frame
# digits: number of digits to round
numeric_columns <- sapply(x, mode) == 'numeric'
x[numeric_columns] <- round(x[numeric_columns], digits)
x
}
data$value<- round_df(data$value, 2)
# stacked area chart
ggplot(data, aes(x=time, y=value, fill=group)) +
geom_area()+
geom_text(aes(x = time + 0.5, y = value, label=ifelse(time == max(time), group, NA)),position = position_stack(vjust = 0.5),check_overlap = TRUE)+
guides(color = FALSE) + theme_bw()+
scale_x_continuous(breaks = scales::pretty_breaks(10)) +
geom_text(aes(label=ifelse(time != min(time) & time != max(time),value, NA)),position = position_stack(vjust = 0.5),check_overlap = TRUE)+
geom_text(aes(x = time + 0.18,label=ifelse(time == min(time),value, NA)),position = position_stack(vjust = 0.5),check_overlap = TRUE)+
geom_text(aes(x = time - 0.18,label=ifelse(time == max(time),value, NA)),position = position_stack(vjust = 0.5),check_overlap = TRUE)
And get
Factor levels but why not letters? That is the next step :)
UPDATED
just converted factor to char data$group <- as.character(data$group)
I have this data frame
df <- data.frame(profile = rep(c(1,2), times = 1, each = 3), depth = c(100, 200, 300), value = 1:3)
This is my plot
ggplot() +
geom_bar(data = df, aes(x = profile, y = - depth, fill = value), stat = "identity")
My problem is the y labels which doesn't correspond to the depth values of the data frame
To help, my desired plot seems like this :
ggplot() +
geom_point(data = df, aes(x = profile, y = depth, colour = value), size = 20) +
xlim(c(0,3))
But with bar intead of points vertically aligned
nb : I don't want to correct it manually in changing ticks with scale_y_discrete(labels = (desired_labels))
Thanks for help
Considering you want a y-axis from 0 to -300, using facet_grid() seems to be a right option without summarising the data together.
ggplot() + geom_bar(data = df, aes(x = as.factor(profile), y = -depth, fill = value), stat = 'identity') + facet_grid(~ value)
I have it !
Thanks for your replies and to this post R, subtract value from previous row, group by
To resume; the data :
df <- data.frame(profile = rep(c(1,2), times = 1, each = 3), depth = c(100, 200, 300), value = 1:3)
Then we compute the depth step of each profile :
df$diff <- ave(df$depth, df$profile, FUN=function(z) c(z[1], diff(z)))
And finally the plot :
ggplot(df, aes(x = factor(profile), y = -diff, fill = value)) + geom_col()