How to change font size of geom_text post ex - r

If I want to change the font size of a geom_text I can use the size parameter. But what if I have a ggplot object which is generated by somebody else (in a function say) and I want to change the font size afterwards? (I could rewrite the function and allow for an additional size parameter, but I want to avoid that).
I played with theme(text = element_text(size = 20)), but this changed every text, but the geom_text? I also tried to replace the respective layer by a new geom_text layer. However, since in the foreign function call the data argument for the geom_text was altered, I get an error about missing aesthetics.
Code
library(ggplot2)
functionICannotControl <- function() {
mdat <- mtcars
mdat$cyl2 <- LETTERS[mdat$cyl]
ggplot(mtcars, aes(x = hp, y = mpg)) + geom_text(aes(label = cyl2), data = mdat)
}
(bp <- functionICannotControl())
## changed only other text elements
bp + theme(text = element_text(size = 20))
## gives an error
bp2 <- bp
bp2$layers[[1]] <- geom_text(size = 20)
bp2
## Error: geom_text requires the following missing aesthetics: label
bp2$layers[[1]] <- geom_text(aes(label = cyl2), size = 20)
bp2
## Error in eval(expr, envir, enclos) : object 'cyl2' not found

OK, I found the solution (and for reference, if somebody is having the same problem). We can change the aes_params slot of the layer:
bp$layers[[1]]$aes_params
## named list()
bp$layers[[1]]$aes_params$size <- 20
bp
N.B. It does help to write a minimal working example because by posing a well structured question, you can learn something about your own problem ;)

Related

ggplot2 mappings changing when using tidy evaluation and aes() instead of aes_string()

I am trying to update some older plot-making code that gives the message:
Warning message: `aes_string()` was deprecated in ggplot2 3.0.0. Please use tidy evaluation ideoms with `aes()`
When I replace aes_string() with aes() and the unquoting !!, I start getting the message "Error: Discrete value supplied to continuous scale" in unexpected places.
Here is a simplified reproducible example:
# Make some test data
set.seed(1)
dat <- data.frame(x=rnorm(100),y=rnorm(100),value=rnorm(100))
xvar <- 'x'
yvar <- 'y'
cvar <- 'value'
# This works, but gives a deprecated warning for use of aes_string()
ggplot(dat,aes_string(x=xvar,y=yvar,color=cvar)) + geom_point() + scale_color_gradientn(colors = rainbow(10))
# This changes the plot to use aes() with !! instead of using aes_string()
# It fails with "Error: Discrete value supplied to continuous scale"
ggplot(dat,aes(x=!!xvar,y=!!yvar,color=!!cvar)) + geom_point() + scale_color_gradientn(colors = rainbow(10))
I haven't been able to get to the bottom of what's causing this, but it looks like the mappings themselves are being handled differently in ggplot - with aes_string() the variable names show up with a ~ at the beginning, and with aes() and !! they do not:
# Capture each plot so it can be examined
plt_working <- ggplot(dat,aes_string(x=xvar,y=yvar,color=cvar)) + geom_point() + scale_color_gradientn(colors = rainbow(10))
plt_broken <- ggplot(dat,aes(x=!!xvar,y=!!yvar,color=!!cvar)) + geom_point() + scale_color_gradientn(colors = rainbow(10))
summary(plt_working) # The second line says "mapping: colour = ~value, x = ~x, y = ~y"
summary(plt_broken) # The second line says "mapping: x = x, y = y, colour = value" (no ~s)
What does the ~ mean? In this context it doesn't seem likely to have anything to do with formulas or facets.
Why does this change make the plot code stop working, and what would be the correct way to update the code so it will still work?
The current (as of 2023) preferred method for using strings inside of aes() is via ggplot's .data object (thank you to Lionel Henry for clarifying the reasoning behind it):
xvar <- 'x'
yvar <- 'y'
cvar <- 'value'
ggplot(dat,aes(x = .data[[xvar]], y = .data[[yvar]], color = .data[[cvar]])) + geom_point() + scale_color_gradientn(colors = rainbow(10))
Alternately, you can wrap your strings in sym(), then use !! to unwrap them inside aes():
set.seed(1)
dat <- data.frame(x=rnorm(100),y=rnorm(100),value=rnorm(100))
xvar <- sym('x')
yvar <- sym('y')
cvar <- sym('value')
ggplot(dat,aes(x=!!xvar,y=!!yvar,color=!!cvar)) + geom_point() + scale_color_gradientn(colors = rainbow(10))

How do you fix warning message: colourbar guide needs continuous scales?

I would like to produce multiple contour plots using ggplot2 and
geom_contour_filled()
but the z values range is too large. To give you a little bit of an idea of what the values are, it ranges from -2,71 to -157,28. So I thought I should change the breaks so it covers all of these values.
The code below is not the data I work with, but it should represent the problem I have:
The data
h_axis <- 10^(seq(log10(0.1), log10(1000),
length.out = 20))
a_axis <- 10^(seq(log10(0.1), log10(1000),
length.out = 20))
comb <- expand.grid(h_axis, a_axis)
h_val <- comb$Var2
a_val <- comb$Var1
values <- seq(-2, -150, length.out = 400)
dt <- data.frame(h = h_val, a = a_val, values)
First, let's say I don't change the breaks. Then, using this code
ggplot(dt, aes(x = log10(h_val), y = log10(a_val), z = values)) +
geom_contour_filled() +
# geom_contour(color = "black", size = 0.1) +
xlab(expression(log[10](h))) +
ylab(expression(log[10](a))) +
guides(fill = guide_colorbar(title = expression('E ||'*g - hat(g)*'||'[2]*'')))
will produce the following figure:
So a lot of the area will be covered by the same colour, which is a problem since my data consists of multiple factors. Factor 1 is covered by the yellow, Factor 2 is covered by the green, and so on.
Then my second approach, is to add
bar <- 10^(seq(log10(-min(values)), log10(-max(values)),
length.out = 100))
and put bar in the geom_contour_filled() like this
geom_contour_filled(breaks = -bar)
Then I get
which is nice! But, in both cases I get the following warning
Warning message:
colourbar guide needs continuous scales.
Also, the legend is not shown on the right side. What do I need to do to fix the warning and how can I make sure that the legend is shown?
Try guide_legend instead of guide_colorbar.

Faulty legend in R with "color_scale_manual"

Can please someone tell me why my legend is not displaying correctly (The point in the legend for Hypericin is filled green and not blue).
Here is my code:
ggplot(df,aes(x=x, y=y))+
labs(list(title='MTT_darktox',x=expression('Concentration['*mu*'M]'),y='Survival[%]'))+
scale_x_continuous(breaks=seq(0,50,2.5))+
scale_y_continuous(breaks=seq(0,120,20))+
expand_limits(y=c(0,120))+
geom_point(data=df,shape = 21, size = 3, aes(colour='Hypericin'), fill='blue')+
geom_errorbar(data=df,aes(ymin=y-sd1, ymax=y+sd1),width = 0.8, colour='blue')+
geom_line(data=df,aes(colour='Hypericin'), size = 0.8)+
geom_point(data=df2,shape = 21, size = 3, aes(colour='#212'), fill='green')+
geom_errorbar(data=df2,aes(ymin=y-sd1, ymax=y+sd1),width = 0.8, colour='green')+
geom_line(data=df2,aes(colour='#212'), size = 0.8)+
scale_colour_manual(name='Batch_Nr', values=c('Hypericin'='blue','#212' ='green'))
Thank you!
R Plot
It would definately help to see some data for reproducability.
Guessing the structure of your data results in something like this.
# create some fake data:
df <- data.frame(x = rep(1:10, 2),
y = c(1/1:10, 1/1:10 + 1),
error = c(rnorm(10, sd = 0.05), rnorm(10, sd = 0.1)),
group = rep(c("Hypericin", "#212"), each = 10))
Which can be plotted like this:
# plot the data:
library(ggplot2)
ggplot(df, aes(x = x, y = y, color = group)) +
geom_line() +
geom_point() +
geom_errorbar(aes(ymin = y - error, ymax = y + error)) +
scale_colour_manual(name='Batch_Nr',
values = c("Hypericin" = "blue", "#212" = "green"))
Which results in a plot like this:
Explanation
First of all, you don't need to add the data = df in the ggplot-functions if you already defined that in the first ggplot-call.
Furthermore, ggplot likes tidy data best (aka. the long-format. Read more about that here http://vita.had.co.nz/papers/tidy-data.pdf). Thus adding two datasets (df, and df2) is possible but merging them and creating every variable in the dataset has the advantage that its also easier for you to understand your data.
Your error (a green point instead of a blue one) came from this confusion. In line 6 you stated that fill = "blue", which you don't change later (i.e., you don't specify something like this: scale_fill_color(...).
Does that give you what you want?
Lastly, for future questions, please make sure that you follow the MWE-principle (Minimal-Working-Example) to make the life of everyone trying to answer the question a bit easier: How to make a great R reproducible example?
Thank you very much for your help! I will consider the merging for future code.
Meanwhile I found another solution to get what I wanted without changing everything (although probably not the cleanest way). I just added another line to override the legend appearance :
guides(colour= guide_legend(override.aes=list(linetype=c(1,1)
,shape=c(16,16))))
resulting in :
R plot new

How to obtain y-axis-labels in ggplot2? [duplicate]

I have created a function for creating a barchart using ggplot.
In my figure I want to overlay the plot with white horizontal bars at the position of the tick marks like in the plot below
p <- ggplot(iris, aes(x = Species, y = Sepal.Width)) +
geom_bar(stat = 'identity')
# By inspection I found the y-tick postions to be c(50,100,150)
p + geom_hline(aes(yintercept = seq(50,150,50)), colour = 'white')
However, I would like to be able to change the data, so I can't use static positions for the lines like in the example. For example I might change Sepal.With to Sepal.Height in the example above.
Can you tell me how to:
get the tick positions from my ggplot; or
get the function that ggplot uses for tick positions so that I can use this to position my lines.
so I can do something like
tickpositions <- ggplot_tickpostion_fun(iris$Sepal.Width)
p + scale_y_continuous(breaks = tickpositions) +
geom_hline(aes(yintercept = tickpositions), colour = 'white')
A possible solution for (1) is to use ggplot_build to grab the content of the plot object. ggplot_build results in "[...] a panel object, which contain all information about [...] breaks".
ggplot_build(p)$layout$panel_ranges[[1]]$y.major_source
# [1] 0 50 100 150
See edit for pre-ggplot2 2.2.0 alternative.
Check out ggplot2::ggplot_build - it can show you lots of details about the plot object. You have to give it a plot object as input. I usually like to str() the result of ggplot_build to see what all the different values it has are.
For example, I see that there is a panel --> ranges --> y.major_source vector that seems to be what you're looking for. So to complete your example:
p <- ggplot() +
geom_bar(data = iris, aes(x = Species, y = Sepal.Width), stat = 'identity')
pb <- ggplot_build(p)
str(p)
y.ticks <- pb$panel$ranges[[1]]$y.major_source
p + geom_hline(aes(yintercept = y.ticks), colour = 'white')
Note that I moved the data argument from the main ggplot function to inside geom_bar, so that geom_line would not try to use the same dataset and throw errors when the number in iris is not a multiple of the number of lines we're drawing. Another option would be to pass a data = data.frame() argument to geom_line; I cannot comment on which one is a more correct solution, or if there's a nicer solution altogether. But the gist of my code still holds :)
For ggplot 3.1.0 this worked for me:
ggplot_build(p)$layout$panel_params[[1]]$y.major_source
#[1] 0 50 100 150
for sure you can. Read the help file for the seq() function.
seq(from = min(), to = max(), len = 5)
and do something like this.
p <- ggplot(iris, aes(x = Species, y = Sepal.Width)) +
geom_bar(stat = 'identity')
p + geom_hline(aes(yintercept = seq(from = min(), to = max(), len = 5)), colour = 'white')

Writing ggplot functions in R with optional arguments

I have a series of ggplot graphs that I'm repeating with a few small variations. I would like to wrap these qplots with their options into a function to avoid a lot of repetition in the code.
My problem is that for some of the graphs I am using the + facet_wrap() option, but for others I am not. I.e. I need the facet wrap to be an optional argument. When it is included the code needs to call the +facet_wrap() with the variable supplied in the facets argument.
So ideally my function would look like this, with facets being an optional argument:
$ qhist(variable, df, heading, facets)
I have tried googling how to add optional arguments and they suggest either passing a default value or using an if loop with the missing() function. I haven't been able to get either to work.
Here is the function that I have written, with the desired functionality of the optional facets argument included too.
$ qhist <- function(variable, df, heading, facets) {
qplot(variable, data = df, geom = "histogram", binwidth = 2000,
xlab = "Salary", ylab = "Noms") +
theme_bw() +
scale_x_continuous(limits=c(40000,250000),
breaks=c(50000,100000,150000,200000,250000),
labels=c("50k","100k","150k","200k","250k")) +
opts(title = heading, plot.title = theme_text(face = "bold",
size = 14), strip.text.x = theme_text(size = 10, face = 'bold'))
# If facets argument supplied add the following, else do not add this code
+ facet_wrap(~ facets)
the way to set up a default is like this:
testFunction <- function( requiredParam, optionalParam=TRUE, alsoOptional=123 ) {
print(requiredParam)
if (optionalParam==TRUE) print("you kept the default for optionalParam")
paste("for alsoOptional you entered", alsoOptional)
}
*EDIT*
Oh, ok... so I think I have a better idea of what you are asking. It looks like you're not sure how to bring the optional facet into the ggplot object. How about this:
qhist <- function(variable, df, heading, facets=NULL) {
d <- qplot(variable, data = df, geom = "histogram", binwidth = 2000,
xlab = "Salary", ylab = "Noms") +
theme_bw() +
scale_x_continuous(limits=c(40000,250000),
breaks=c(50000,100000,150000,200000,250000),
labels=c("50k","100k","150k","200k","250k")) +
opts(title = heading, plot.title = theme_text(face = "bold",
size = 14), strip.text.x = theme_text(size = 10, face = 'bold'))
# If facets argument supplied add the following, else do not add this code
if (is.null(facets)==FALSE) d <- d + facet_wrap(as.formula(paste("~", facets)))
d
return(d)
}
I have not tested this code at all. But the general idea is that the facet_wrap expects a formula, so if the facets are passed as a character string you can build a formula with as.formula() and then add it to the plot object.
If I were doing it, I would have the function accept an optional facet formula and then pass that facet formula directly into the facet_wrap. That would negate the need for the as.formula() call to convert the text into a formula.
Probably, the best way is to stop using such unusual variable names including commas or spaces.
As a workaround, here is an extension of #JDLong's answer. The trick is to rename the facet variable.
f <- function(dat, facet = NULL) {
if(!missing(facet)) {
names(dat)[which(names(dat) == facet)] <- ".facet."
ff <- facet_wrap(~.facet.)
} else {
ff <- list()
}
qplot(x, y, data = dat) + ff
}
d <- data.frame(x = 1:10, y = 1:10, "o,o" = gl(2,5), check.names=F)
f(d, "o,o")
f(d)
Note that you can also use missing(facets) to check if the facets argument was specified or not. If you use #JD Long's solution, it would look something like this:
qhist <- function(variable, df, heading, facets) {
... insert #JD Longs' solution ...
if (!missing(facets)) d <- d + facet_wrap(as.formula(paste("~", facets)))
return(d)
}
...Note that I also changed the default argument from facets=NULL to just facets.
Many R functions use missing arguments like this, but in general I tend to prefer #JD Long's variant of using a default argument value (like NULL or NA) when possible. But sometimes there is no good default value...

Resources