ggplot line or point plotting conditionally - r

I'm using ggplot to write a bunch of plots inside a function. I want to pass another flag to the function so that I can choose while calling the function that whether to plot lines or points.
Currently I'm doing it like this:
plot2pdfHD = function(opdata, dir = 'plots'){
#... do something ...
plots <- list()
for (i in seq(strikes)){
#... do something ...
plots[[i]] <- ggplot(sset, aes(x = TIMESTAMP, y = value, col = optype)) +
geom_line() + labs(x = "Time", y = 'values') +
#... do something ...
}
pdf(paste0(dir, '/', Sys.Date(), '.pdf'), width=16, height=10)
for(i in seq(length(plots)))
tryCatch({print(plots[[i]])}, error = function(e) NULL)
dev.off()
}
I want to add a flag so that by setting appropriate value to the flag I can switch between geom_line() and geom_point() while calling the function.
Addition:
Can it be done without repeating the additional call part, i.e. #... do something ...? I am hoping for an answer that does that.
Also sset is a subset of the opdata.

Maybe this is what you're looking for? I like #arvi1000's answer---nice and clear---but you can put the if statement inside a single ggplot addition expression:
type = "line"
## also try with
# type = "point"
ggplot(mtcars, aes(x = wt, y = mpg)) + {
if(type == "point") geom_point() else geom_line()
} +
theme_bw()
For multiple layers, you could do something like this:
gg = ggplot(mtcars, aes(x = wt, y = mpg))
{
if(type == "point") {
gg + geom_point()
} else {
gg + geom_line() + stat_smooth()
}
} + theme_bw()
(Of course, adding the theme_bw() to the original gg definition would be cleaner, but this demonstrates that it can be added later.)

Plain old if block?
plot2pdfHD = function(opdata, dir = 'plots', plot_type){
plots <- list()
for (i in seq(strikes)) {
# base gg call
p <- ggplot(sset, aes(x = TIMESTAMP, y = value, col = optype))
# add geom layer based on content of argument:
if(plot_type == 'line') p <- p + geom_line()
if(plot_type == 'point') p <- p + geom_point()
# add additional params and assign into list item
plots[[i]] <- p + labs(x = "Time", y = 'values')
#...
}
# ...
}
Other notes:
I'm assuming you are doing something to make sset different before each call, otherwise you are going to get a list of identical plots
lapply might be better than a for loop here, esp since you are wanting a list object as the result anyway

Related

for-loop to create ggplots

I trying to make boxplots with ggplot2.
The code I have to make the boxplots with the format that I want is as follows:
p <- ggplot(mg_data, aes(x=Treatment, y=CD68, color=Treatment)) +
geom_boxplot(mg_data, mapping=aes(x=Treatment, y=CD68))
p+ theme_classic() + geom_jitter(shape=16, position=position_jitter(0.2))
I can was able to use the following code to make looped boxplots:
variables <- mg_data %>%
select(10:17)
for(i in variables) {
print(ggplot(mg_data, aes(x = Treatment, y = i, color=Treatment)) +
geom_boxplot())
}
With this code I get the boxplots however, they do not have the name label of what variable is being select for the y-axis, unlike the original code when not using the for loop. I also do not know how to add the formating code to the loop:
p + theme_classic() + geom_jitter(shape=16, position=position_jitter(0.2))
Here is a way. I have tested with built-in data set iris, just change the data name and selected columns and it will work.
suppressPackageStartupMessages({
library(dplyr)
library(ggplot2)
})
variables <- iris %>%
select(1:4) %>%
names()
for(i in variables) {
g <- ggplot(iris, aes(x = Species, y = get(i), color=Species)) +
geom_boxplot() +
ylab(i)
print(g)
}
Edit
Answering to a comment by user TarJae, reproduced here because answers are less deleted than comments:
Could you please expand with saving all four files. Many thanks.
The code above can be made to save the plots with a ggsave instruction at the loop end. The filename is the variable name and the plot is the default, the return value of last_plot().
for(i in variables) {
g <- ggplot(iris, aes(x = Species, y = get(i), color=Species)) +
geom_boxplot() +
ylab(i)
print(g)
ggsave(paste0(i, ".png"), device = "png")
}
Try this:
variables <- mg_data %>%
colnames() %>%
`[`(10:17)
for (i in variables) {
print(ggplot(mg_data, aes(
x = Treatment, y = {{i}}, color = Treatment
)) +
geom_boxplot())
}
Another option is to use lapply. It's approximately the same as using a loop, but it hides the actual looping part and can make your code look a little cleaner.
variables = iris %>%
select(1:4) %>%
names()
lapply(variables, function(x) {
ggplot(iris, aes(x = Species, y = get(x), color=Species)) +
geom_boxplot() + ylab(x)
})

R: ggplot - Different Title for each object in a plot list

currently I am trying to making a plot list with ggplot from a list of data frames (94 time series). Then I want to export the plots to a PDF. This, so far, was successful using following code:
plot.list = lapply(HR_clean, function(x) {
y = length(x)
z = data.frame("HR" = x, "Time" = rep(1:y, 1))
ggplot(z, aes(x = Time, y = HR)) +
theme_bw() +
geom_line(linetype = "solid") +
ggtitle("Plot Title")
})
ggsave(
filename = "plots2.pdf",
plot = marrangeGrob(plot.list, nrow=1, ncol=1),
width = 15, height = 9
)
However, I also want that the main title of each plot is equal name of the corresponding list object. Perhaps anyone knows a smart solution for this problem.
Best,
Johnson
I couldn't test this (since you are not providing example data) but this should work using purrr's imap():
plot.list <- purrr::imap(HR_clean, function(x, name) {
y <- length(x)
z <- data.frame("HR" = x, "Time" = rep(1:y, 1))
ggplot(z, aes(x = Time, y = HR)) +
theme_bw() +
geom_line(linetype = "solid") +
ggtitle(name)
})

automagically using labels (haven semantics) in ggplot2 plots

I'm plotting data marked up using haven semantics, i.e. variables and values have labels defined via attributes.
Often, these labels are also what I want in my axis titles and ticks.
library(ggplot2)
mtcars$mpg = haven::labelled(mtcars$mpg, labels = c("low" = 10, "high" = 30))
attributes(mtcars$mpg)$label = "miles per gallon"
ggplot(mtcars, aes(mpg, cyl)) + geom_point() +
scale_x_continuous(attributes(mtcars$mpg)$label,
breaks = attributes(mtcars$mpg)$labels,
labels = names(attributes(mtcars$mpg)$labels))
Could I write a helper that replaces that laborious scale_x_continuous statement with something that can more easily be iterated? E.g. something like
scale_x_continuous(label_from_attr, breaks = breaks_from_attr, labels = value_labels_from_attr). Or maybe even + add_labels_from_attributes() to replace the whole thing?
I'm aware that I can write/use helpers like Hmisc::label to slightly shorten the attribute-code above, but that's not what I want here.
I don't have a good scale, but you can use a function like this:
label_x <- function(p) {
b <- ggplot_build(p)
x <- b$plot$data[[b$plot$labels$x]]
p + scale_x_continuous(
attributes(x)$label,
breaks = attributes(x)$labels,
labels = names(attributes(x)$labels)
)
}
Then use as (+ won't do):
p <- ggplot(mtcars, aes(mpg, cyl)) + geom_point()
label_x(p)
Alternatively, use a pipe:
mtcars %>% { ggplot(., aes(mpg, cyl)) + geom_point() } %>% label_x()
Old solution
use_labelled <- function(l, axis = "x") {
if (axis == "x") {
scale_x_continuous(attributes(l)$label,
breaks = attributes(l)$labels,
labels = names(attributes(l)$labels))
}
if (axis == "y") {
scale_y_continuous(attributes(l)$label,
breaks = attributes(l)$labels,
labels = names(attributes(l)$labels))
}
}
Then you just give:
ggplot(mtcars, aes(mpg, cyl)) + geom_point() + use_labelled(mtcars$cyl)
Or for the y-axis:
ggplot(mtcars, aes(cyl, mpg)) + geom_point() + use_labelled(mtcars$cyl, "y")
Another approach is to write a wrapper for ggplot() that has its own class. Then attributes have full visibility when the corresponding print method is called. See ?ag.print from package 'yamlet' (0.2.1).
library(ggplot2)
library(yamlet)
library(magrittr)
mtcars$disp %<>% structure(label = 'displacement', unit = 'cu. in.')
mtcars$mpg %<>% structure(label = 'mileage', unit = 'miles/gallon')
mtcars$am %<>% factor(levels = c(0,1), labels = c('automatic','manual'))
mtcars$am %<>% structure(label = 'transmission')
agplot(mtcars, aes(disp, mpg, color = am)) + geom_point()

Facet labels involving a greek symbol

Suppose I have the data and plot as follows:
mydata = data.frame(x=rnorm(4), y=runif(4), tau=c(0,0,1,1))
ggplot(mydata) + geom_point(aes(x=x, y=y)) + facet_wrap(~ tau)
I would like the facet labels to read "tau=0" and "tau=1", respectively, with tau formatted as its greek symbol. I know from another question that using the labeller label_parsed will format the letter tau by itself, but the equal sign seems to complicate things. An ideal solution would not require me to change the data (i.e. make tau a factor and name its levels), but I will take whatever works :)
here a solution with facet_grid adn indexing the tau by its levels.
mydata = data.frame(x=rnorm(4), y=runif(4), tau=c(0,0,1,1))
ggplot(mydata) + geom_point(aes(x=x, y=y)) +
facet_grid(~ tau,labeller = label_bquote(tau ^ .(x)))
Edit To get the "tau=0" and "tau=1"
facet_grid(~ tau,labeller = label_bquote(tau == .(x)))
Edit2 second variable sigma
I find this solution, by defining a custom labeller. Hope someone ( ggplot2 guys ) give me a simpler solution.
my.label_bquote <- function (expr1 = (tau == .(x)),expr2 = (sigma == .(x)))
{
quoted1<- substitute(expr1)
quoted2 <- substitute(expr2)
function(variable, value) {
value <- as.character(value)
if(variable == 'tau')
lapply(value, function(x)
eval(substitute(bquote(expr1, list(x = x)),list(expr1 = quoted1))))
else
lapply(value, function(x)
eval(substitute(bquote(expr2, list(x = x)),list(expr2 = quoted2))))
}
}
mydata = data.frame(x=rnorm(4), y=runif(4), tau=c(0,0,1,1),sigma=c(2,2,3,3))
ggplot(mydata) + geom_point(aes(x=x, y=y)) +
facet_grid(sigma ~ tau,labeller = my.label_bquote())
There is an easier solution to this. The simulated data variable names have been changed for clarity in how they work within the labeller argument.
mydata = data.frame(x=rnorm(4), y=runif(4), tauvar=c(0,0,1,1),sigmavar=c(2,2,3,3))
ggplot(mydata) +
geom_point(aes(x=x, y=y)) +
facet_grid(sigmavar ~ tauvar,labeller = label_bquote(sigma==.(sigmavar),
tau==.(tauvar)))

Apply two transformations on one axis

I have found coord_trans, but I'd like to apply log10 and
reverse to my x-axis. I tried applying two transformation
ggplot(table) + aes(color=Vowel, x=F1, y=F2) + geom_point() + coord_trans(x="log10", y="log10") + coord_trans(x="reverse", y="reverse")
but only the first one was applied. So I tried linking them
ggplot(table) + aes(color=Vowel, x=F2, y=F1) + geom_point() + coord_trans(x=c("log10", "reverse"), y=c("log10", "reverse"))
Which gives me a plain error.
'c("log10_trans", "reverse_trans")' is not a function, character or symbol
How do I chain them?
You can define new transformations using trans_new.
library(scales)
log10_rev_trans <- trans_new(
"log10_rev",
function(x) log10(rev(x)),
function(x) rev(10 ^ (x)),
log_breaks(10),
domain = c(1e-100, Inf)
)
p <- ggplot(mtcars, aes(wt, mpg)) +
geom_point()
p + coord_trans(y = log10_rev_trans)
A quick and easy way is to apply one of the transformations directly to the data and use the other with the plot function.
e.g.
ggplot(iris, aes(log10(Sepal.Length), log10(Sepal.Width), colour = Species)) +
geom_point() + coord_trans(x="reverse", y="reverse")
Note: the reverse transformation does not work with the iris data but you get the idea.
I wandered in here looking for a 'composition of scales' function. I think one might be able to write such a thing as follows:
# compose transforms a and b, applying b first, then a:
`%::%` <- function(atrans,btrans) {
mytran <- scales::trans_new(name = paste(btrans$name,'then',atrans$name),
transform = function(x) { atrans$transform(btrans$transform(x)) },
inverse = function(y) { btrans$inverse(atrans$inverse(y)) },
domain = btrans$domain, # this could use improvement...
breaks = btrans$breaks, # not clear how this should work, tbh
format = btrans$format)
}
ph <- ggplot(mtcars, aes(wt, mpg)) +
geom_point() +
scale_y_continuous(trans=scales::reverse_trans() %::% scales::log10_trans())
print(ph)

Resources