I have a dataset I'm plotting, with facets by variables (in the toy dataset - densities of 2 species). I need to use the actual variable names to do 2 things: 1) italicize species names, and 2) have the 2 in n/m2 properly superscripted (or ASCII-ed, whichever easier).
It's similar to this, but I can't seem to make it work for my case.
toy data
library(ggplot2)
df <- data.frame(x = 1:10, y = 1:10,
z = rep(c("Species1 density (n/m2)", "Species2 density (m/m2)"), each = 5),
z1 = rep(c("Area1", "Area2", "Area3", "Area4", "Area5"), each = 2))
ggplot(df) + geom_point(aes(x = x, y = y)) + facet_grid(z1 ~ z)
I get an error (variable z not found) when I try to use the code in the answer naively. How do I get around having 2 variables in the facetting?
A little modification gets the code from your link to work. I've changed the code to use data_frame to stop the character vector being converted to a factor, and taken the common information out of the codes so it can be added via the labeller (otherwise it would be a pain to make half the text italic)
library(tidyverse)
df <- data_frame(
x = 1:10,
y = 1:10,
z = rep(c("Species1", "Species2"), each = 5),
z1 = rep(c("Area1", "Area2", "Area3", "Area4", "Area5"), each = 2)
)
ggplot(df) +
geom_point(aes(x = x, y = y)) +
facet_grid(z1 ~ z, labeller = label_bquote(col = italic(.(z))~density~m^2))
Related
I want to create a combination plot using plot_grid from the cowplot package.
The two plots that I want to combine use a log scale. Of the data plotted, some is negative, which gets dropped.
I can quite easily produce a decent result using facet_wrap that looks like this:
library(tidyverse)
tibble(x = rnorm(100),
y = rnorm(100),
type = "A") %>%
bind_rows(tibble(x = rnorm(100, mean = 10),
y = rnorm(100, mean = 10),
type = "B")) %>%
ggplot(aes(y = y, x = x)) +
geom_point() +
facet_wrap(~type)
But in my particular situation, I can't use facet_wrap because I want to give the panels A and B different x-axis labels and want to change the number format slightly (e.g. adding a $ sign to the axis ticks of panel A and a % sign to panel B).
Therefore I use plot_grid:
tibble(x = rnorm(100),
y = rnorm(100),
type = "A") %>%
ggplot(aes(y = y, x = x)) +
geom_point() +
scale_y_log10() -> a
tibble(x = rnorm(100, mean = 10),
y = rnorm(100, mean = 10),
type = "B") %>%
ggplot(aes(y = y, x = x)) +
geom_point() +
scale_y_log10() -> b
cowplot::plot_grid(a,b)
Now the problem is that the axis is completely distorted (this would be equal to scales = "free_y" in facet_wrap)
So therefore I attempt to set the limits/ranges for both plots manually by choosing the min and max from both plots:
lims <- c(min(layer_scales(a)$y$range$range, layer_scales(b)$y$range$range),
max(layer_scales(a)$y$range$range, layer_scales(b)$y$range$range))
cowplot::plot_grid(a + ylim(lims),b + ylim(lims))
But now the result is this:
So essentially I want to replicate the scales="fixed" in facet_wrap using plot_grid
Any ideas?
many thanks!
The issue is that you provide y axis limits in log10 scale as returned by layer_scales. You need to convert it to actual values.
lims = 10^c(min(layer_scales(a)$y$range$range, layer_scales(b)$y$range$range),
max(layer_scales(a)$y$range$range, layer_scales(b)$y$range$range))
Alternatively, you can compute the range of the actual data.
I am trying to construct a facet plot using ggplot2 with an annotation that varies from one facet to the next. The annotation is to be located using the plot area coordinates between 0 and 1, rather than the usual (x,y) coordinates, and is to be in the same location for every facet. The annotation is to be constructed using the y aesthetic and the paste0() function.
My reprex shows one case that works, but this case does not include the part that comes from the y aesthetic and the annotation does not vary among the facets. The reprex also shows a second case where the percentage change in the last (most recent) value for the y aesthetic is added to the annotation, and this does not work. It is this second case that I want to solve.
The reprex uses the ggpp package, but I have also tried using annotation_custom instead of ggpp. However I have not been able to get that to work either. Any help much appreciated.
Here is my reprex:
# Reprex for facets with placed annotation
library(ggplot2)
library(ggpp)
PC <- function(x) {y <- round(100*(x/lag(x)-1),1)}
df <- data.frame(tm=1:25,A=sample(1:100,25,replace=T),
B=sample(1:100,25,replace=T),C=sample(1:100,25,replace=T),
D=sample(1:100,25,replace=T))
df <- tidyr::pivot_longer(df,cols=2:5,names_to="City",values_to="Value")
# This works:
ggplot(df,aes(x=tm,y=Value))+
geom_line()+
scale_y_continuous(lim=c(-10,100))+
ggpp::geom_text_npc(aes(npcx = x, npcy = y, label=label),
data = data.frame(x = 0.05, y = 0.05,
label='% change in various cities'))+
facet_wrap(~City,scale="free_y")
# But this does not work:
ggplot(df,aes(x=tm,y=Value))+
geom_line()+
scale_y_continuous(lim=c(-10,100))+
ggpp::geom_text_npc(aes(npcx = x, npcy = y, label=label),
data = data.frame(x = 0.05, y = 0.05,
label=paste0("Last change in this city ",PC(y)[25],'%')))+
facet_wrap(~City,scale="free_y")
This solution below is a bit complicated, there are probably simpler ones, but it works.
1. Function PC()
Without loading package dplyr, your function PC is calling stats::lag, not dplyr::lag. And assigning to y without returning its value. The right version is
PC <- function(x) {round(100*(x/dplyr::lag(x) - 1), 1)}
2. The data
The plot is created with data = df but then, when plotting the labels the data set changes and the y value no longer comes from df.
The ggpp::geom_text_npc layer doesn't compute PC(y) correctly because its data argument only is self-referring to y. The data.frame is ill formed. This y is not the one in df.
A way to correct this is to first note that the labels to be plotted are 4, one per city and compute the last change value beforehand. This is very simple:
Value <- with(df, tapply(Value, City, \(y) PC(y)[length(y)]))
Value
# A B C D
# -24.1 -16.7 -91.3 46.9
The labels data then becomes
df_labels <- data.frame(
x = rep(0.05, length(Value)), y = rep(0.05, length(Value)),
City = names(Value),
label = paste0("Last change in this city ", Value, "%")
)
3. The plot
Full reproducible example, from top to bottom.
# Reprex for facets with placed annotation
suppressPackageStartupMessages({
library(ggplot2)
library(ggpp)
})
set.seed(2022)
PC <- function(x) {y <- round(100*(x/dplyr::lag(x) - 1), 1)}
df <- data.frame(tm=1:25,A=sample(1:100,25,replace=T),
B=sample(1:100,25,replace=T),
C=sample(1:100,25,replace=T),
D=sample(1:100,25,replace=T))
df <- tidyr::pivot_longer(df,cols=2:5,names_to="City",values_to="Value")
Value <- with(df, tapply(Value, City, \(y) PC(y)[length(y)]))
df_labels <- data.frame(
x = rep(0.05, length(Value)), y = rep(0.05, length(Value)),
City = names(Value),
label = paste0("Last change in this city ", Value, "%")
)
ggplot(df, aes(x = tm, y = Value)) +
geom_line() +
scale_y_continuous(lim = c(-10, 100)) +
ggpp::geom_text_npc(
data = df_labels,
mapping = aes(
npcx = x, npcy = y,
label = label
)
) +
facet_wrap(~ City, scale = "free_y")
Created on 2022-08-08 by the reprex package (v2.0.1)
I would like to create multiple plots at one page, where I am iteration over different Y variables over the same X. = i.e. I want one plot per one Y. Usually, I would copy and paste my ggplot with just changed Y value, store individual plots as p.y1, p.y2 and plot all of them using grid.arrange(p.y1, p.y2) like here:
This approach is not very fun when I have 10 different Y variables, and I want to plot all of them. I wonder how to make the process more efficient?
I thought that I can simply create a vector of Y (colnames of df) and then loop through them to create multiple plots. But, it seems that my output plots are not correct to pass to grid.arrange(), and I can not plot them neither.
How can I loop through multiple Ys, and then arrange all plots on one page? As I do not have multiple factors, I probably cannot use facet_grid nor facet_wrap.
Here is my dummy example for two Ys: y1 and y2
set.seed(5)
df <- data.frame(x = rep(c(1:5), 2),
y1 = rnorm(10)*3+2,
y2 = rnorm(10),
group = rep(c("a", "b"), each = 5))
# Example of simple line ggplot
ggplot(df, aes(x = x,
y = y2, # here I can set either y1, y2...
group = group,
color = group)) +
geom_line()
Now, iterate over the vectors of Ys and store output plots in a list:
# create vector of my Ys
my.s<-c("y1", "y2")
# Loop over list of y to create different plots
outPlots<- list()
for (i in my.s) {
print(i)
my.plot <-
ggplot(df, aes_string(x = "x",
y = i,
group = "group",
color = "group")) +
geom_line()
# print(plot)
outPlots <- append(outPlots, my.plot)
}
Intendent plotting of multiple graphs on one page: does not work because of Error in gList(list(data.x1 = 1L, data.x2 = 2L, data.x3 = 3L, data.x4 = 4L, : only 'grobs' allowed in "gList"
grid.arrange(outPlots)
I propose another solution based on this post.
Plotfunction <- function(y){my.plot <-
ggplot(df, aes_string(x = "x",
y = y,
group = "group",
color = "group")) +
geom_line()}
n <- ceiling(sqrt(length(my.s)))
do.call("grid.arrange",
c(lapply(my.s, Plotfunction), ncol = n, nrow = n))
You could try this. I hope this helps.
library(reshape2)
Melted <- melt(df,id.vars = c('x','group'))
#Plot
ggplot(Melted,aes(x=x,y=value,group=group,color=group))+
geom_line()+
facet_wrap(~variable,ncol = 1,scales = 'free')+theme_bw()
I need to create a point graph using the "ggplot" library based on a binary column of a dataframe.
df <- c(1,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1)
I need a point to be created every time the value "1" appears in the column, and all points are on the same graph. Thanks.
If the binary column you talk about is associated to some other variables, then I think this might work:
(I've just created some random x and y which are the same length as the binary 0, 1s you provided)
x <- rnorm(22)
y <- x^2 + rnorm(22, sd = 0.3)
df <- data.frame("x" = x, "y" = y,
"binary" = c(1,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1))
library(ggplot2)
# this is the plot with all the points
ggplot(data = df, mapping = aes(x = x, y = y)) + geom_point()
# this is the plot with only the points for which the "binary" variable is 1
ggplot(data = subset(df, binary == 1), mapping = aes(x = x, y = y)) + geom_point()
# this is the plot with all points where they are coloured by whether "binary" is 0 or 1
ggplot(data = df, mapping = aes(x = x, y = y, colour = as.factor(binary))) + geom_point()
Something like this?
library(ggplot2)
y <- df
is.na(y) <- y == 0
ggplot(data = data.frame(x = seq_along(y), y), mapping = aes(x, y)) +
geom_point() +
scale_y_continuous(breaks = c(0, 1),
labels = c("0" = "0", "1" = "1"),
limits = c(0, 1))
It only plots points where df == 1, not the zeros. If you also want those, don't run the code line starting is.na(y).
Not sure exactly what you are asking, but here are a few options. Since your data structure is not a data frame, I've renamed it test. First, dotplot with ggplot:
library(ggplot2)
ggplot(as.data.frame(test), aes(x=test)) + geom_dotplot()
Or you could do the same thing as a bar:
qplot(test, geom="bar")
Or, a primitive base R quick look:
plot(test, pch=16, cex=3)
I have a set of data like below:
pos A C G T
0 0.291398 0.190061 0.315722 0.202818
1 0.315597 0.227511 0.175448 0.281445
2 0.252149 0.194597 0.222815 0.330438
Then I imported the table:
library(ggplot2)
d = read.table(tablename, sep = '\t', header = T)
d = d[2:5]
data.frame(t(d))
And I got a reformatted table as below:
X1 X2 X3
A 0.291398 0.315597 0.252149
C 0.190061 0.227511 0.194597
G 0.315722 0.175448 0.222815
T 0.202818 0.281445 0.330438
However, when I tried to plot it:
qplot(X1, data = d, geom = 'histogram')
It gives the image below:
And what I want should be like:(I used libreoffice, so the color and the width and other parameters do not matter)
May I know how to correct my code to make this shape?
Any help is appreciated. Sorry but I am really new to R and ggplot2.
You aren't telling the plot what you want as your Y value. The X1 choice is the value you got, not the base, and everything is present once, so you get all 1s.
You want X1 as your Y and base as your X.
To fix your plot, from d:
d$base<-rownames(d)
ggplot(d,aes(x=base,y=X1))+geom_bar(stat="identity")
or using qplot nomenclature:
d$base<-rownames(d)
qplot(data = d, x = base, y = X1, geom = 'histogram', stat = "identity")
Edit: Here's how I would plot it for all rows:
library(reshape2)
d1 <- melt(d, id = "pos")
ggplot(d1, aes(x = variable, y = value, fill = factor(pos))) +
geom_bar(stat = "identity", position = "dodge")