Is there an elegant way in ggplot2 to make geom_text/geom_label inherit theme specifications like a base_family?
Or asked the other way round: Can I specify a theme that also applies to geom_text/geom_label?
Example:
I want text/labels to look exactly like the axis.text as specified in the theme...
Obviously I could add the specifications manually as optional arguments to geom_text, but I want it to inherit the specifications "automatically"...
library("ggplot2")
ggplot(mtcars, aes(x = mpg,
y = hp,
label = row.names(mtcars))) +
geom_point() +
geom_text() +
theme_minimal(base_family = "Courier")
Addition: A solution that works with ggrepel::geom_text_repel/geom_label_repel as well would be perfect...
You can
Setting Overall font
Firstly, depending on the system you will need to check which fonts are available. As I am running on Windows I am using the following:
install.packages("extrafont")
library(extrafont)
windowsFonts() # check which fonts are available
The theme_set function lets you specify the overall themes for ggplot. So therefore theme_set(theme_minimal(base_family = "Times New Roman")) lets you define the fonts for the plot.
Make Labels Inherit Font
To make the labels inherit this text, there are two things we need to use:
update_geom_defaults lets you update the geometry object styling for future plots in ggplot: http://ggplot2.tidyverse.org/reference/update_defaults.html
theme_get()$text$family extracts the font of the current global ggplot theme.
By combining these two, the label styles can be updated as follows:
# Change the settings
update_geom_defaults("text", list(colour = "grey20", family = theme_get()$text$family))
update_geom_defaults("text_repel", list(colour = "grey20", family = theme_get()$text$family))
Results
theme_set(theme_minimal(base_family = "Times New Roman"))
# Change the settings
update_geom_defaults("text", list(colour = "grey20", family = theme_get()$text$family))
# Basic Plot
ggplot(mtcars, aes(x = mpg,
y = hp,
label = row.names(mtcars))) +
geom_point() +
geom_text()
# works with ggrepel
update_geom_defaults("text_repel", list(colour = "grey20", family = theme_get()$text$family))
library(ggrepel)
ggplot(mtcars, aes(x = mpg,
y = hp,
label = row.names(mtcars))) +
geom_point() +
geom_text_repel()
Related
I would like to specify a font for all text when making a ggplot. I found I can set the base size under ggplot's selected theme but cannot find a clear example of setting to a monospaced font such as say Courier or preferably Roboto Mono for the entire plot.
This solution looked like it should work:
Can't change fonts in ggplot/geom_text
But no joy in my attempt below
install.packages("extrafont")
library(extrafont)
loadfonts(device = "win")
require(tidyverse)
ggplot(mtcars, aes(x = mpg, y = cyl, group = carb)) +
geom_point() +
theme_light(base_size = 15, base_family = "Roboto Mono")
Going along with #Allan Cameron 's response.
windowsFonts('Roboto Mono'=windowsFont("Roboto Mono"))
ggplot(mtcars, aes(x = mpg, y = cyl, group = carb)) +
geom_point() +
theme_light(base_size = 15, base_family = windowsFonts()$`Roboto Mono`)
Is it possible to make a theme that changes the shape of the legend icon/symbol that is used to identify the different color in a plot?
What I mean is that if you make a line plot:
library(ggplot2)
ggplot(iris, aes(x=Sepal.Length, y = Sepal.Width, color=Species)) +
geom_line()
You will see 'thin' lines identifying each different group. I don't prefer this.
What I would like is to always make my color identifiers nice solid squares/blocks like this:
ggplot(iris, aes(x=Sepal.Length, y = Sepal.Width, color=Species, fill=Species)) +
geom_bar(stat='identity')
I'm wondering if there is an option that I can add to a custom ggplot theme to enable this by default? I have some custom made themes for plots and I'd love to be able to add this in, as sometimes its really hard to make out the very faint lines or dots. A solid square is much more noticeable.
I don't think theme() allows you to override specific aesthetic parameters in the legend key symbols. It deals with the legend key's size, background, etc., while draw_key_XXX covers the key symbols' appearance.
However, if the concern is about re-typing, you can add guides(...) to your customized theme:
theme_customized <- function(...){
list(guides(color = guide_legend(override.aes = list(size = 10))),
# optional: the base theme you modify from
theme_light(),
# customized theme options for your theme
# (I'm using axis.text / panel.grid for illustration)
theme(axis.text = element_text(size = 15),
panel.grid.minor.y = element_blank()),
# any theme options that you may want to set
# on an ad hoc basis
theme(...))
}
Using the customized theme:
gridExtra::grid.arrange(
# with ggplot's default theme_grey
ggplot(iris, aes(x=Sepal.Length, y = Sepal.Width, color=Species)) +
geom_line(),
# customized theme with default options
ggplot(iris, aes(x=Sepal.Length, y = Sepal.Width, color=Species)) +
geom_line() +
theme_customized(),
# customized theme with additional adhoc specifications
ggplot(iris, aes(x=Sepal.Length, y = Sepal.Width, color=Species)) +
geom_line() +
theme_customized(axis.title = element_text(color = "blue"),
panel.background = element_rect(fill = "darkgrey")),
ncol = 1
)
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.
I'm making many plots and want to set a default color for the data labels without having to pass the color argument to every geom_text call. I can do it for the plot titles and axes, but not the data labels.
# Example of how to set default color for other text elements
library(ggplot2)
theme_set(theme_bw() + theme(text = element_text(color = "red"),
axis.text = element_text(color = "red")))
ggplot(mtcars, aes(x = cyl, label = ..count..)) +
geom_bar() +
geom_text(stat = "count") +
labs(title = "title")
Unfortunately, I believe theme elements are only intended to apply to non-data-related elements of the plot, meaning the theme does not cover the text in geom_text. The default color "black" is hard-coded in the source of geom_text, so as far as I know, there's not a simple way to override it. (Though, if someone cares to correct me, excellent!)
However, one simple solution that may help streamline things is to create a wrapper function that will return a geom_text with all the defaults that you will be passing over and over. For example:
geom_text_wrap <- function(col="red", ...) {
geom_text(col=col, ...)
}
can be used in place of geom_text directly, and will, by default, create red text. So the following will create red text without you having to specify it directly in the plot creation.
ggplot(mtcars, aes(x = cyl, label = ..count..)) +
geom_bar() +
geom_text_wrap(stat="count") +
labs(title = "title")
Note: If you really are creating a ton of similar plots to the point that you are tiring of specifying repetitive arguments, you may consider writing a function that will create the complete graph objects programmatically. That will depend on your specific use-case.
I'm having trouble changing the title and the look of my legend in ggplot, right now it looks like this:
But I want the title to be "Whatever I please" and the colors representing the different data to be larger.(e.g. taking up the whole square instead of being a tiny circle)
For the title I tried changing:
theme(legend.position="top", legend.title='Whatever I please')
But ggplot doesn't accept this. How can I make this adjustments?
ggplot(...) + geom_point(...) +
labs(color = "Your title here") +
guides(color = guide_legend(override.aes = list(size = 5)))
You may need to change the size in the guide to get the look you want.
You could also use the name and guide arguments of the scale_colour_discrete function to do that:
library(ggplot2)
ggplot(mtcars, aes(x = hp, y = qsec, col = as.factor(cyl)))+
geom_point() +
scale_colour_discrete(name = "Whatever I please",
guide = guide_legend(override.aes = list(size = 10)))
The legend.title argument of the theme function only accepts element_text values (so your 'Whatever I please' there won't work), and is used mostly to change font related aspects of the legend title, not the text itself.