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
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)
})
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)
})
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()
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)))
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)