How to use a function to transform axis values with ggplot2? - r

Instead of 'log2', I want to use 'log2/(log2-1)'
sp <- ggplot(cars, aes(x = speed, y = dist)) + geom_point()
sp
sp + scale_x_continuous(trans='log2') +
scale_y_continuous(trans='log2')
When I try, I get:
object 'log2/(log2-1)_trans' of mode 'function' was not found
Thanks.

You have to define the function first, and its inverse for the labelling, then use the trans_new function from the scales package:
log2_1 <- function(x) log2(x)/(log2(x)-1)
antilog2_1 <- function(x) 2^(x/(x-1))
sp + scale_x_continuous(trans = trans_new("log2_1",
transform=log2_1,
inverse=antilog2_1)) +
scale_y_continuous(trans = trans_new("log2_1",
transform=log2_1,
inverse=antilog2_1))

Related

ggplot scale_x_log10() with bigger base than 10 for the logarithm

Is there an easy way to scale a ggplot by log base 20 or higher? This works great:
ggplot(data, aes(x, y)) + geom_line() + scale_x_log10()
Unfortunately base 10 too small. There's a more general scale_x_continuous function that takes a trans argument, but there doesn't appear to be any log transforms higher than base 10.
Here's a worked example of creating a new trans object to use in your plot:
Initial plot
library(ggplot2)
df <- data.frame(x = 1:10, y = 10^(1:10))
p <- ggplot(df, aes(x, y)) + geom_line()
p
With log scale using base 100
p + scale_y_continuous(trans = scales::trans_new(name = "log100",
transform = function(x) log(x, 100),
inverse = function(x) 100^x,
domain = c(1e-16, Inf)),
breaks = scales::breaks_log(5, 100),
labels = scales::comma)
Created on 2020-12-07 by the reprex package (v0.3.0)
The scales package provides transforms to the scale_x_continuous() function. You can either use the built-in flexible log transform or create your own using the trans_new() function.
Built-in with base-20:
require(scales)
base=20
p1 <- ggplot(mpg, aes(displ, hwy)) +
geom_point()
p1 + scale_y_continuous(trans = scales::log_trans(base))
Make your own transform:
require(scales)
logTrans <- function(base=20){
trans_new(name='logT',
transform=function(y){
return(log(y, base=base))
},
inverse=function(y){
return(base^y)
})
}
base=20
p1 + scale_y_p1 <- ggplot(mpg, aes(displ, hwy)) +
geom_point()
p1 + continuous(trans = logTrans(base=base))

changing the facet_wrap labels using labeller in ggplot2

In my ggplot below, I'm trying to change the 10 facet labels of facet_wrap using labeller(sch.id=paste0("sch.id:", unique(ten$sch.id))).
However, the plot shows NA instead of the correct facet labels, I wonder what the fix is?
library(ggplot2)
hsb <- read.csv('https://raw.githubusercontent.com/rnorouzian/e/master/hsb.csv')
ten <- subset(hsb, sch.id %in% unique(sch.id)[1:10])
p <- ten %>% ggplot() + aes(ses, math) + geom_point() +
facet_wrap(~sch.id) + geom_smooth(method = "lm", se = FALSE)
p + facet_wrap(~sch.id, labeller = labeller(sch.id=paste0("sch.id:", unique(ten$sch.id)))) ## HERE ##
The problem seems to be that you are passing a variable to the labeller function but facet_wrap already passes its own faceting variable. A conflict occurs and the result are NA's.
The solution is to create a labeller function as a function of a variable x (or any other name as long as it's not the faceting variables' names) and then coerce to labeller with as_labeller.
Note that there is no need for unique, just like there is no need for it in the facet_wrap formula.
p <- ten %>% ggplot() + aes(ses, math) + geom_point() +
geom_smooth(method = "lm", formula = y ~ x, se = FALSE)
cust_labeller <- function(x) paste0("sch.id:", x)
p + facet_wrap(~ sch.id,
labeller = as_labeller(cust_labeller)) ## HERE ##
I think the easiest way would be to change sch.id before plotting.
library(ggplot2)
ten$sch.id <- paste0("sch.id:", ten$sch.id)
ggplot(ten) + aes(ses, math) +
geom_point() +
geom_smooth(method = "lm", se = FALSE) +
facet_wrap(~sch.id)
If you don't want to modify your data and want to use the labeller argument you can create a named vector and use it in labeller.
cust_label <- setNames(paste0("sch.id:", unique(ten$sch.id)), unique(ten$sch.id))
ggplot(ten) + aes(ses, math) +
geom_point() +
geom_smooth(method = "lm", se = FALSE) +
facet_wrap(~sch.id, labeller = as_labeller(cust_label))

ggplot: modify coord_cartesian() values dynamically

Is there a way to modify the plot coordinates using coord_cartesian() in a way that is dynamic based on the data in the ggplot call?
For example:
ggplot(cars, aes(x = speed, y = dist)) +
geom_point() +
coord_cartesian(xlim = c(min(.$speed), max(.$speed) + 10))
This doesn't work, nor does using .data$speed.
You can use the magrittr and dplyr pipe operator (%>%) to pass data into the ggplot call.
cars %>%
{ggplot(., aes(speed, dist)) +
geom_point() +
coord_cartesian(xlim = c(min(.$speed), max(.$speed) + 10))
}
Note that now you need to explicitly identify the data argument at the beginning of the ggplot call using the . pronoun.
It's a bit hacky but you can add a blank geom and add 10 to the y in the aesthetics.
ggplot(cars, aes(x = speed, y = dist)) +
geom_point() +
geom_blank(aes(y = dist + 10))

R + ggplot: geom_txt label not recognize a variable in function call

I'm an R/ggplot newbie switching over from MatLab.
I would like to create a function using ggplot with linear regression equation printed on the graph (which is discussed in Adding Regression Line Equation and R2 on graph). But here, I am trying to build a function with it but wasn't successful.
I kept getting an error -
"Error in eval(expr, envir, enclos) : object 'label' not found".
One workaround is to define "label" variable outside of the function but I just don't understand why this doesn't work.
Can anyone explain why?
df <- data.frame(x = c(1:100))
df$y <- 2 + 3 * df$x + rnorm(100, sd = 40)
f <- function(DS, x, y, z) {
label <- z
print(label)
ggplot(DS, aes(x=x, y=y)) +
geom_point() +
labs(y=y) +
labs(title=y) +
xlim(0,5)+
ylim(0,5)+
geom_smooth(method="lm", se=FALSE)+
geom_text (aes(x=1, y=4, label=label))
}
f(df, x, y, "aaa") #execution line
See the following code:
library(ggplot2)
df <- data.frame(x = c(1:100))
df$y <- 2 + 3 * df$x + rnorm(100, sd = 40)
f <- function(DS, x, y, z) {
label.df = data.frame(x=1, y=4, label=z)
ggplot(DS, aes_string(x=x, y=y)) +
geom_point() +
labs(y=y) +
labs(title=y) +
geom_smooth(method="lm", se=FALSE)+
geom_text (aes(x=x, y=y, label=label), label.df)
}
f(df, "x", "y", "aaa")
There were a few fixes about your code:
The data you are using in geom_text is the same you have defined in ggplot() unless you change it. Here I have created a temporary data.frame for this purpose called label.df.
The xlim() and ylim() functions were filtering most of your data points, since the range of x and y are much larger than the limits you defined in the original code.
When you want to pass the names of the columns of your data.frame to be used for displaying the graph it would be easier to pass their names as strings (i.e. "x"). This way, the aes() function is also changed to aes_string().
Here is the result:
Edit
Thanks to #Gregor, a simpler version would be:
f <- function(DS, x, y, z) {
ggplot(DS, aes_string(x=x, y=y)) +
geom_point() +
labs(y=y) +
labs(title=y) +
geom_smooth(method="lm", se=FALSE)+
annotate(geom="text", x=1, y=4, label=z)
}

Error in trying to write a plotting function in ggplot2

I am trying to write a function in ggplot2 and obtain this error message:
Error in layout_base(data, vars, drop = drop) :
At least one layer must contain all variables used for facetting
Here is my code:
growth.plot<-function(data,x,y,fac){
gp <- ggplot(data = data,aes(x = x, y = y))
gp <- gp + geom_point() + facet_wrap(~ fac)
return(gp)
}
growth.plot(data=mydata, x=x.var, y=y.var,fac= fac.var)
If I try without the function, the plot appears perfectly
gp1 <- ggplot(data = mydata,aes(x = x.var), y = y.var))
gp1+ geom_point()+ facet_wrap(~ fac.var) # this works
Here is reproducible solution where your x, y, and fac arguments must be passed as character:
library(ggplot2)
make_plot = function(data, x, y, fac) {
p = ggplot(data, aes_string(x=x, y=y, colour=fac)) +
geom_point(size=3) +
facet_wrap(as.formula(paste("~", fac)))
return(p)
}
p = make_plot(iris, x="Sepal.Length", y="Petal.Length", fac="Species")
ggsave("iris_plot.png", plot=p, height=4, width=8, dpi=120)
Thanks to commenters #Roland and #aosmith for pointing the way to this solution.

Resources