R ggplot2 using variable expressions in legend name - r

I am trying to plot a series of time series with ggplot2 that sometimes have greek names. As the plot uses dynamic names (i.e. the names of the variables are stored within another variable) I am having troubles to get it to work.
Here is an example:
# create some data
df <- data.frame(time = rep(1:10, 3),
variable = rep(letters[1:3], each = 10),
val = rnorm(30))
# create a variable for the group name
nam <- expression("alpha[i]")
library(ggplot2)
# plot the data as a line
ggplot(df, aes(x = time, y = val, color = variable)) +
geom_line() +
# Option 1: Does not work
scale_color_discrete(name = eval(nam))
# Option 2: works but has no variable input
# scale_color_discrete(name = expression(alpha[i]))
Do you have any idea of how I can evaluate the variable nam to be displayed as the name of the legend as in option 2?
Thank you very much!

Using this code
# create some data
df <- data.frame(time = rep(1:10, 3),
variable = rep(letters[1:3], each = 10),
val = rnorm(30))
# create a variable for the group name
nam <- expression(alpha[i])
library(ggplot2)
# plot the data as a line
ggplot(df, aes(x = time, y = val, color = variable)) +
geom_line() +
# Option 1: Does not work
scale_color_discrete(name = nam)
# Option 2: works but has no variable input
# scale_color_discrete(name = expression(alpha[i]))
This gives me the plot you probably wanna see. No eval in name = eval(name) and no blockquotes in the assignment nam <- expression(alpha[i])

Probably this will work:
nam <- "alpha[i]"
...
scale_color_discrete(name = eval(parse(text= nam)))

Related

Customize facet_wrap plot label in R?

I'm creating a facet_wrap plot in R, and I'm trying to automate the labeller. I can create a custom label manually, using this code:
library(ggplot2)
library(tidyverse)
df <- data.frame(a = rep(c(1/8,1/4,1/2), each = 100),
b = rep(c("A", "B", "C", "D"), each = 25),
x = rnorm(100))
names <- c(
`0.125` = "alpha~`=`~1/8",
`0.25` = "alpha~`=`~1/4",
`0.5` = "alpha~`=`~1/2"
)
df %>% ggplot() +
geom_density(aes(x = x, colour = b))+
facet_wrap(~a, labeller = labeller(a = as_labeller(names, label_parsed)))
The above code produces this plot:
facetplot
As you can see I'm creating the custom names in the names variable and then passing that to the labeller argument. I want to come up with a way to automate this process. So I can use any vector of names. Any suggestions?
I think I have a possible solution. If a user supplies a personalised vector of values, say, vec <- c(1/5, 'Hello', 3.14) then Im looping through each value of vector and pasting the unicode value for alpha and turning it into a list. After this I am creating a kind of dummy function that contains my new list of label titles and Im passing that to the labeller function:
# EDIT: removed loop with help from comments!
#nam <- NULL
# for(i in 1:(length(vec))){
# nam[i] <- list(paste0('\u03b1',"=", vec[i]))
#}
nam <- paste0('\u03b1',"=", vec)
custLab <- function (x){
nam
}
p <- df %>% ggplot() +
geom_density(aes(x = x, colour = b))+
facet_wrap(~a, labeller = as_labeller((custLab)))
This produces the following:

Creating and labelling points on a geom_line() graph [duplicate]

This question already has an answer here:
label specific point in ggplot2
(1 answer)
Closed 1 year ago.
Basically, I want to make a graph that shows where different "analysts" chose a certain point on the graph.
This is what the base graph looks like
.
This is what I want to produce
.
I have a separate dataframe called sum_data that summarizes the time choices made by each analyst. It looks like this. The following is the code used to create the plot:
gqplot <- ggplot(Qdata,
aes(x = date,
y = cfs))+
labs(#title = paste(watershedID,"_",event),
x = "Date",
y = "Flow [cfs]")+
geom_line(colour = "#000099")+
# Show plot
gqplot
Hey what you need is a data.frame that contains the choices of those 2 people (like your sum_data) and then use geom_point().
Here is an example. I made up data and code etc because you didn't provide a completely reproducible example.
# Library
library(ggplot2)
# Seed for exact reproducibility
set.seed(20210307)
# Main data frame
main_data <- data.frame(x = 1:10, y = rnorm(10))
# Analyst data frame
analyst_choice <- data.frame(x = c(2, 3), y = main_data[2:3, 'y'], analyst = c('John', 'Paul'))
# Create plot
ggplot(main_data, aes(x = x, y = y)) +
geom_line() +
geom_point(data = analyst_choice, aes(x = x, y = y, colour = analyst), size = 10, shape = 4)
That's what this code produces:

How to plot a(n unknown) number of data series as geom_line in same chart

My first Q here, so please go lightly if I'm out of step anywhere.
I'm trying to code R to produce a single chart to contain a number of data series lines. The number of data series may vary but will be provided in the data frame. I have tried to rearrange another thread's content to print the geom_line , but not successfully.
The logic is:
#desire to replace loop of 1:5 with ncol(df)
print(ggplot(df,aes(x=time))
for (i in 1:5) {
print (+ geom_line(aes(y=df[,i]))
}
#functioning geom point loops ggplot production:
for (i in 1:5) {
print(ggplot(df,aes(x=time,y=df[,i]))+geom_point())
}
#functioning multi-line ggplot where n is explicit:
ggplot(data=df, aes(x=time), group=1) +
geom_line(aes(y=df$`3`))+
geom_line(aes(y=df$`4`))
The functioning example code produces n number of point charts, 5 in this case. I would like just one chart to contain n line series.
This may be similar to How to plot n dimensional matrix? for which there are currently no relevant answers
Any contributions much appreciated, thanks
You can use gather from tidyverse "world" to do that.
As you didn't supply a sample data I used mtcars.
I created two data.frames one with 3 columns one with 9. In each one of them I plotted all of the variables against the variable mpg.
library(tidyverse)
df3Columns <- mtcars[, 1:4]
df9Columns <- mtcars[, 1:10]
df3Columns %>%
gather(var, value, -mpg) %>%
ggplot(aes(mpg, value, group = var, color = var)) +
geom_line()
df9Columns %>%
gather(var, value, -mpg) %>%
ggplot(aes(mpg, value, group = var, color = var)) +
geom_line()
Edit - using the sample data in comments.
library(tidyverse)
df %>%
rownames_to_column("time") %>%
gather(var, value, -time) %>%
ggplot(aes(time, value, group = var, color = var)) +
geom_line()
Sample data:
df <- structure(list("39083" = c(96, 100, 100), "39090" = c(99, 100, 100), "39097" = c(99, 100, 100)), row.names = 3:5, class = "data.frame")
To strictly answer your question, you can simply store your ggplot in a variable and add the geom_line one by one:
df <- structure(list("39083" = c(96, 100, 100), "39090" = c(99, 100, 100), "39097" = c(99, 100, 100)), row.names = 3:5, class = "data.frame")
g <- ggplot(df, aes(x = 1:nrow(df)))
for (i in colnames(df))
{
g <- g + geom_line(y = df[,i])
}
g <- g + scale_y_continuous(limits = c(min(df), max(df)))
print(g)
However, this is not a very convenient solution. I would highly recommend to refactor your data frame to be more ggplot style.
df.ultimate <- data.frame(time = numeric(), value = numeric(), group = character())
for (i in colnames(df))
{
df.ultimate <- rbind(df.ultimate, data.frame(time = 1:nrow(df), value = df[, i], group = i))
}
g <- ggplot(df.ultimate, aes(x = time, y = value, color = group))
g <- g + geom_line()
print(g)
A one-line solution:
ggplot(data.frame(time = rep(1:nrow(df), ncol(df)),
value = as.vector(as.matrix(df)),
group = rep(colnames(df), each = nrow(df))),
aes(x = time, y = value, color = group)) + geom_line()

How to use direct.label() with simple (two variables) ggplot2 chart

Here is a simple ggplot chart for two variables:
library("ggplot2")
library("directlabels")
library("tibble")
df <- tibble(
number = 1:10,
var1 = runif(10)*10,
var2 = runif(10)*10
)
ggplot(df, aes(number))+
geom_line(aes(y=var1), color='red')+
geom_line(aes(y=var2), color='blue')
Is it possible to label the last value of var1 and var2 using the expression like that:
direct.label(df, 'last.points')
In my case I get an error:
Error in UseMethod("direct.label") :
no applicable method for 'direct.label' applied to an object of
class
Maria, you initially need to structure your data frame by "stacking data". I like to use the melt function of the reshape2 package. This will allow you to use only one geom_line.
Later you need to generate an object from ggplot2. And this object you must apply the directlabels package.
library(ggplot2)
library(directlabels)
library(tibble)
library(dplyr)
library(reshape2)
set.seed(1)
df <- tibble::tibble(number = 1:10,
var1 = runif(10)*10,
var2 = runif(10)*10)
df <- df %>%
reshape2::melt(id.vars = "number")
p <- ggplot2::ggplot(df) +
geom_line(aes(x = number, y = value, col = variable), show.legend = F) +
scale_color_manual(values = c("red", "blue"))
p
directlabels::direct.label(p, 'last.points')

How to add ggplot legend of two different lines R?

I need to add a legend of the two lines (best fit line and 45 degree line) on TOP of my two plots. Sorry I don't know how to add plots! Please please please help me, I really appreciate it!!!!
Here is an example
type=factor(rep(c("A","B","C"),5))
xvariable=seq(1,15)
yvariable=2*xvariable+rnorm(15,0,2)
newdata=data.frame(type,xvariable,yvariable)
p = ggplot(newdata,aes(x=xvariable,y=yvariable))
p+geom_point(size=3)+ facet_wrap(~ type) +
geom_abline(intercept =0, slope =1,color="red",size=1)+
stat_smooth(method="lm", se=FALSE,size=1)
Here is another approach which uses aesthetic mapping to string constants to identify different groups and create a legend.
First an alternate way to create your test data (and naming it DF instead of newdata)
DF <- data.frame(type = factor(rep(c("A", "B", "C"), 5)),
xvariable = 1:15,
yvariable = 2 * (1:15) + rnorm(15, 0, 2))
Now the ggplot code. Note that for both geom_abline and stat_smooth, the colour is set inside and aes call which means each of the two values used will be mapped to a different color and a guide (legend) will be created for that mapping.
ggplot(DF, aes(x = xvariable, y = yvariable)) +
geom_point(size = 3) +
geom_abline(aes(colour="one-to-one"), intercept =0, slope = 1, size = 1) +
stat_smooth(aes(colour="best fit"), method = "lm", se = FALSE, size = 1) +
facet_wrap(~ type) +
scale_colour_discrete("")
Try this:
# original data
type <- factor(rep(c("A", "B", "C"), 5))
x <- 1:15
y <- 2 * x + rnorm(15, 0, 2)
df <- data.frame(type, x, y)
# create a copy of original data, but set y = x
# this data will be used for the one-to-one line
df2 <- data.frame(type, x, y = x)
# bind original and 'one-to-one data' together
df3 <- rbind.data.frame(df, df2)
# create a grouping variable to separate stat_smoothers based on original and one-to-one data
df3$grp <- as.factor(rep(1:2, each = nrow(df)))
# plot
# use original data for points
# use 'double data' for abline and one-to-one line, set colours by group
ggplot(df, aes(x = x, y = y)) +
geom_point(size = 3) +
facet_wrap(~ type) +
stat_smooth(data = df3, aes(colour = grp), method = "lm", se = FALSE, size = 1) +
scale_colour_manual(values = c("red","blue"),
labels = c("abline", "one-to-one"),
name = "") +
theme(legend.position = "top")
# If you rather want to stack the two keys in the legend you can add:
# guide = guide_legend(direction = "vertical")
#...as argument in scale_colour_manual
Please note that this solution does not extrapolate the one-to-one line outside the range of your data, which seemed to be the case for the original geom_abline.

Resources