I know how to change the default colour in bar charts blue
update_geom_defaults("bar", list(fill = "blue"))
but how do I change the stat component. I tried
update_geom_defaults("bar", list(stat = "identity"))
but after I attempt a ggplot() + geom_bar(...) I get the error message Mapping a variable to y and also using stat="bin". How do I actually change the defaults?
I noticed that
> update_geom_defaults
function (geom, new)
{
g <- Geom$find(geom)
old <- g$default_aes()
aes <- defaults(new, old)
g$default_aes <- eval(substitute(function(.) aes, list(aes = aes)))
}
<environment: namespace:ggplot2>
seems to only apply the update to aesthetics.
update_geom_defaults and update_stat_defaults are functions to change the default aesthetic mapping.
IFIIK, There is no function to change the default stats, but you can easily do the job by, e.g.,
geom_bar_i <- function(...) geom_bar(..., stat = "identity")
ggplot(mtcars, aes(x = am, y = vs)) + geom_bar_i()
Related
I am new to programming and coding, trying to learn R in the Google course.
They have given several examples for visuals using the ggplot functions, but they have used the aes() in two ways.
First:
ggplot(data=palmerpenguins) + geom_point(mapping = aes(x = bill_length_mm,y = body_mass_g))
The aes() function is inside the geom_point() function.
Then they show:
ggplot(data, aes(x=distance, y= dep_delay, color=carrier, size=air_time, shape = carrier)) + geom_point()
Now the aes() function is in the ggplot() function, where they specify the dataset.
What is the reason for the switch? It seems like aes() can go in either place. Is this true? For something that is so specific like coding, it's confusing why you could do it either way. Any explanation would be appreciated. Thanks
If you only have one layer, it really doesn't matter. Each later (geom) can have it's own set of mappings. If you add it to the ggplot() call, that's the "default" mapping that will be used if the later doesn't specify it's own. You can acually add the aes() outside the ggplot() and geom_ calls and that will also act at the default. There are all the same
ggplot(data=penguins) +
geom_point(mapping = aes(x = bill_length_mm, y = body_mass_g))
ggplot(penguins, aes(x = bill_length_mm, y = body_mass_g)) +
geom_point()
ggplot(penguins) +
aes(x = bill_length_mm, y = body_mass_g) +
geom_point()
Here's an example with two different layers with different mappings
ggplot(penguins) +
aes(x=island, y=bill_length_mm) +
geom_boxplot() +
geom_jitter(aes(color=sex))
Note that the color will only apply to the jitter later, not to the boxplot layer.
If you define the mapping (use aes()) inside the ggplot call, you create a set of default mapping values for all the attached geoms.
If you want to apply different mappings for each geom you add, you can define them in an aes() call within the geom itself.
I am trying to use fill by barplot (Proportion) with one categorical variable, but got the error message:Error in rep(value[[k]], length.out = n) : attempt to replicate an object of type 'closure'.
The dataset I am using is diamond under ggplot2, here is my code:
bar_1 <- ggplot(data = diamonds) + geom_bar(
mapping = aes(x = cut, y=stat(prop), group=1), fill=cut),
show.legend = FALSE)
Can anyone let me know the problem?
Since cut is a variable in your data frame, it needs to be mapped to its aesthetic, in this case fill, inside of the aes()
bar_1 <- ggplot(data = diamonds) + geom_bar(
mapping = aes(x = cut, y=stat(prop), group=1, fill=cut),
show.legend = FALSE)
As a result of placing fill=cut outside of aes, cut was interpreted as the function base::cut(), an object of type closure, which threw an error when ggplot attempted to assign it to the fill aesthetic of geom_bar
I've got a function that uses ggplot. I'd like to either pass it a variable to use for the fill aesthetic, or use a different colour when I don't pass in anything.
The if/else statement does that for the function below, but my actual function is a bit more complicated and has a few if/else branches, so I'd like to minimise them.
Would it be possible to set the default fill for geom_bar() to "blue", but have that overridden if I pass in a fill aesthetic?
Alternatively, I was thinking of creating a list of arguments to be passed to geom_bar(), based on the arguments passed to my function, and splicing it in using !!!. I haven't really got my head around tidyeval/quasiquotation yet though so I don't quite know how that would work.
I'm open to other solutions too though.
library(ggplot2)
plotter <- function(x = mtcars, fill = NULL) {
p <- ggplot(x, aes(factor(cyl)))
# I don't like this if/else statement
if (!is.null(fill)) {
p <- p + geom_bar(mapping = aes_string(group = fill, fill = fill))
} else {
p <- p + geom_bar(fill = "blue")
}
p
}
plotter()
plotter(fill = "as.factor(gear)")
To make my figure suitable for black-white printing, I mapped one variable with "shape", "lty", "color" together.
ggplot(df, aes(x=time, y=mean,
shape=quality,
lty=quality,
color=quality))
I got the figure like,
I would like to make part of legends as subscribs, with the codes:
labels=c(expression(Pol[(Art)]), expression(Pol['(Aca-)']), expression(Pol['(Aca-)']))
Unfortunately, when I put the "label" in color or shape, it makes the legend quite complex, like,
Is it possible to map "shape", "color","lty" to one varible, and set the subscript, but keep them in one set of legend?
To change the labels of a categorical scale, you use scale_*_discrete(labels = ...). Here you just need to do that for color, shape, and linetype.
You should avoid using lty = generally; that synonym is permitted for compatibility with base R, but it's not universally supported throughout ggplot2.
I changed your labels to be closer to what I think you meant (the third entry is now "Aca+" instead of a repeat of "Aca-") and to make them left-align better (by adding an invisible "+" to the first one to create the appropriate spacing).
lab1 <- c(expression(Pol[(Art)*phantom("+")]),
expression(Pol['(Aca-)']),
expression(Pol['(Aca+)']))
library(ggplot2)
ggplot(mtcars,
aes(wt, mpg,
color = factor(cyl),
shape = factor(cyl),
linetype = factor(cyl))) +
geom_point() +
stat_smooth(se = F) +
scale_color_discrete(labels = lab1) +
scale_shape_discrete(labels = lab1) +
scale_linetype_discrete(labels = lab1)
If you find yourself needing to repeat exact copies of a function like this, there's two workarounds:
Relabel the data itself - OR -
Use purrr::invoke_map to iterate over the functions
library(purrr)
ggplot(mtcars,
aes(wt, mpg,
color = factor(cyl),
shape = factor(cyl),
linetype = factor(cyl))) +
geom_point() +
stat_smooth(se = F) +
invoke_map(list(scale_color_discrete,
scale_linetype_discrete,
scale_shape_discrete),
labels = lab1)
Update:
This approach is mostly fine, but now the expression(...) syntax has a superior alternative, the excellent markdown-based {ggtext} package: https://github.com/wilkelab/ggtext
To change to this method, use a (optionally, named) vector of labels that look like this:
library(ggtext)
lab1 <- c(
`4` = "Pol<sub>(Art)</sub>",
`6` = "Pol<sub>(Aca-)</sub>",
`8` = "Pol<sub>(Aca+)</sub>"
)
And then add this line to your theme:
... +
theme(
legend..text = element_markdown()
)
The advantages over the other method are that:
markdown syntax is a lot easier to search for help online and
now those labels can be stored in the actual data as a column, rather than passing them separately to each geom
You can use that new column as your aesthetic mapping [ggplot(..., aes(color = my_new_column, linetype = my_new_column, ...)] instead of having to pass extra labels in each layer using the purrr::invoke method.
In the following example a function returns a theme, which is altered by some extend (in this minimum example just some extreme ugly modifications...). Adding this function the first time to a ggplot does not do anything, but adding it to any further plot it works as intenden. How can I make sure, that the function works properly alreay in its first application, or where is my error in thinking?
require(ggplot2)
# Minimal example: function returning some theme with modifications
mytheme <- function(size = 3) {
th.my <- theme_set(theme_bw(base_size=size))
th.my$axis.ticks$size = 1
return (th.my)
}
# Plot something, applying theme function first time
fig1 <- ggplot(data = mtcars, aes(x = mpg)) +
geom_point(aes(y = hp)) +
mytheme()
print(fig1)
# Now exactly the same, again
fig2 <- ggplot(data = mtcars, aes(x = mpg)) +
geom_point(aes(y = hp)) +
mytheme()
print(fig2)
As one can see in the following plots, the first time the theme was not applied, but the second time it worked...
This is because theme_set changes the default for future calls to ggplot, it does not change the "current" theme. If you create your own theme function, it should return a list of changes. Don't bother with theme_set. This should work
mytheme <- function(size = 3) {
theme_bw(base_size=size) + theme(axis.ticks= element_line(size = 1))
}
ggplot(data = mtcars, aes(x = mpg)) +
geom_point(aes(y = hp)) +
mytheme()
Or if you wanted these themes to apply to all future plots, you would just run
theme_set(mytheme())
ggplot(data = mtcars, aes(x = mpg)) +
geom_point(aes(y = hp))
# note we don't need to add it to the plot this time since we've
# set it as the default