I am using the R package cooccur and cannot figure out how to change the font size in the associated graphics. The par() method does not seem to work.
Here is the example given by the package:
data(finches)
cooccur.finches <- cooccur(mat=finches,
type="spp_site",
thresh=TRUE,
spp_names=TRUE)
plot(cooccur.finches)
I am trying to change the font size of the species, the title and the legend to no avail on the heat map that is produced. Any help would be MUCH appreciated. Thanks!
Unfortunately the author didn't use defined theme inside the function, so if you want to not mess up the other customizations in place, this should work:
p <- plot(cooccur.finches)
p + theme_bw(base_size = 28) +
theme(axis.text = element_blank(),
axis.ticks = element_blank(),
plot.title = element_text(vjust = -4, face = "bold"),
panel.background = element_rect(fill = "white", colour = "white"),
panel.grid = element_blank()
legend.position = c(0.9, 0.5))
You can also use this code to set the size of the legend or title independently, e.g.
p + theme(plot.title = element_text(vjust = -4, face = "bold", size = 36))
Most unfortunately, this won't change the size of the species labels because they are set with geom_text(). To alter them, you'll have to hack the function yourself cooccur:::plot.cooccur. You only need to modify the last line:
p + geom_text(data = dfids, aes(label = X1), hjust = 1, vjust = 0,
angle = -22.5)
# change to
p + geom_text(data = dfids, aes(label = X1), hjust = 1, vjust = 0,
angle = -22.5, size = 24)
It is a ggplot2 plot not a base one. So par will not work.
p <- plot(cooccur.finches)
p + theme(text = element_text(size = 10)) ## change text font size
or
p + theme_grey(base_size = 18) ## chnage all font size.
Author of Cooccur here. Sorry for the hassle with the text sizes being hard to adjust. I will deal with this when I get a chance.
Not a permanent solution, but easier than changing the function each time for the species labels, is to just directly re-assign the value in the ggplot object:
p$layers[[2]]$geom_params$size <- 10
Hope that helps. I might be a bit late to the scene...
Related
The problem
I have some code that creates a map with numerous points, annotated with some stats, on a monthly basis. This worked fine until I updated ggplot2 to 3.3.6, after which the plots have broken and I've not been able to figure out the solution. As far as I can tell, the issue lies in the ggsave() call, but I don't know what has changed and how to fix it.
There are two main issues that have come up. But to illustrate, I will attach below comparison images of the "good" and "bad" versions (click links to see full-size).
Good points
Bad points
The good version has uniformly coloured points/squares while the latter has strange points coloured irregularly.
Good text
Bad text
The non-breaking space is formatted properly in the good version, while it appears as a box in the bad version.
Debugging attempts
One potential cause I noted for the irregular points was some updates in the works for the "size" parameter (see this blog post). Such things have happened in the past as well (see this for example). However, this update is claimed to be for the next release, and moreover like I said, I have a hunch the issue I'm facing has something to do with ggsave(). And regardless, I already tried tweaking the size and stroke of the geom_point() but haven't been able to recover the old version properly.
The RStudio plot device doesn't indicate any issue with the points, and using the png() method instead of ggsave() to write produces the correct/"good" version.
png(filename = "map_cov_plain.png",
units = "in", width = 8, height = 11, bg = "transparent", res = 300)
print(map_cov_plain)
dev.off()
I tried reverting to ggplot 3.3.5 but this did not fix the issue. Moreover, two others tried the same code on their separate systems, both with ggplot 3.3.6, but only one replicated my issue while the other produced the good version. Nevertheless, the code was certainly working fine until July, only after which I updated several packages and the code broke.
For the record, I have ensured that the issue is not with the data. So, although I have used data until June to illustrate the good version, that same dataset generates the bad maps when the code is run now (i.e., after the updates).
I am hoping someone with a better understanding of the package and the update will be able to figure out what exactly the breaking change was!
Other links
ggsave() doesn't render custom fonts when saving (+workaround)
I also posted this as an issue in the ggplot2 repo; apologies for cross-posting, but wasn't sure which one was more appropriate, and felt a SO post might still be useful for future users with the same problem.
Reprex
There are two files required for the reprex below to work:
.RData file with the necessary data objects (link)
logo image required in one of the maps (link)
library(lubridate)
library(tidyverse)
library(glue)
library(magick)
library(scales) # for comma format of numbers
library(grid)
# loading objects
load("reprex.RData")
map_cov_logo <- image_convert(image_read("bcilogo-framed.png"), matte = T)
map_cov_text <- glue::glue("{label_comma()(data_cov$LOCATIONS)} locations
{label_comma()(data_cov$LISTS)} lists
{label_comma()(data_cov$HOURS)} hours
{label_comma()(data_cov$PEOPLE)} people
{label_comma()(data_cov$STATES)} states/UTs
{label_comma()(data_cov$DISTRICTS)} districts
{label_comma()(data_cov$SPECIES)} species
{round(data_cov$OBSERVATIONS, 1)} million observations")
map_cov_footer <- glue::glue("Data until September 2022")
### map with annotations of stats and BCI logo ###
map_cov_annot <- ggplot() +
geom_polygon(data = indiamap, aes(x = long, y = lat, group = group),
colour = NA, fill = "black")+
geom_point(data = data_loc, aes(x = LONGITUDE, y = LATITUDE),
colour = "#fcfa53", size = 0.05, stroke = 0) +
# scale_x_continuous(expand = c(0,0)) +
# scale_y_continuous(expand = c(0,0)) +
theme_bw() +
theme(axis.line = element_blank(),
axis.text.x = element_blank(),
axis.text.y = element_blank(),
axis.ticks = element_blank(),
axis.title.x = element_blank(),
axis.title.y = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.border = element_blank(),
# panel.border = element_blank(),
plot.background = element_rect(fill = "black", colour = NA),
panel.background = element_rect(fill = "black", colour = NA),
plot.title = element_text(hjust = 0.5)) +
coord_cartesian(clip = "off") +
theme(plot.margin = unit(c(2,2,0,23), "lines")) +
annotation_raster(map_cov_logo,
ymin = 4.5, ymax = 6.5,
xmin = 46.5, xmax = 53.1) +
annotation_custom(textGrob(label = map_cov_text,
hjust = 0,
gp = gpar(col = "#FCFA53", cex = 1.5)),
ymin = 19, ymax = 31,
xmin = 40, xmax = 53) +
annotation_custom(textGrob(label = map_cov_footer,
hjust = 0,
gp = gpar(col = "#D2D5DA", cex = 1.0)),
ymin = 15, ymax = 16,
xmin = 40, xmax = 53)
ggsave(map_cov_annot, file = "map_cov_annot.png", device = "png",
units = "in", width = 13, height = 9, bg = "transparent", dpi = 300)
### plain map without annotations ###
map_cov_plain <- ggplot() +
geom_polygon(data = indiamap, aes(x = long, y = lat, group = group),
colour = NA, fill = "black")+
geom_point(data = data_loc, aes(x = LONGITUDE, y = LATITUDE),
colour = "#fcfa53", size = 0.05, stroke = 0.1) +
# scale_x_continuous(expand = c(0,0)) +
# scale_y_continuous(expand = c(0,0)) +
theme_bw() +
theme(axis.line = element_blank(),
axis.text.x = element_blank(),
axis.text.y = element_blank(),
axis.ticks = element_blank(),
axis.title.x = element_blank(),
axis.title.y = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.border = element_blank(),
plot.margin = unit(c(0, 0, 0, 0), "cm"),
# panel.border = element_blank(),
plot.background = element_rect(fill = "black", colour = NA),
panel.background = element_rect(fill = "black", colour = NA),
plot.title = element_text(hjust = 0.5)) +
coord_map()
ggsave(map_cov_plain, file = "map_cov_plain.png", device = "png",
units = "in", width = 8, height = 11, bg = "transparent", dpi = 300)
I think this comes down to taste, and you prefer the result of the rendering without anti-aliasing. It looks bolder and sharper because the cells that are partially activated are shown at full brightness, in contrast with fully black adjacent pixels. Mssr. Pederson argues that the anti-aliased version is in some respects a truer depiction of the underlying data, since it will perceptually give the dots more consistent weight and spacing that corresponds to their actual size and placement.
Two examples:
set.seed(42)
library(ggplot2)
df_rand <- data.frame(x = runif(1000), y = runif(1000))
ggplot(df_rand, aes(x,y)) +
geom_point(colour = "#fcfa53", size = 0.01, stroke = 0) +
theme_void() +
theme(plot.background = element_rect(fill = "black", colour = NA),
panel.background = element_rect(fill = "black", colour = NA))
ggsave("rand_no_anti-alias.png", device = png,
units = "px", width = 100, height = 100)
ggsave("rand_ragg_anti-alias.png", device = ragg::agg_png(),
units = "px", width = 100, height = 100)
Of these two, you prefer the former for your use case and particular settings.
df_grid <- data.frame(expand.grid(x = 1:30, y = 1:30))
ggplot(df_grid, aes(x,y)) +
geom_point(colour = "#fcfa53", size = 0.01, stroke = 0) +
theme_void() +
theme(plot.background = element_rect(fill = "black", colour = NA),
panel.background = element_rect(fill = "black", colour = NA))
ggsave("grid_no_anti-alias.png", device = png,
units = "px", width = 100, height = 100)
ggsave("grid_ragg_anti-alias.png", device = ragg::agg_png(),
units = "px", width = 100, height = 100)
Note here that the version without anti-aliasing creates phantom groupings out of a uniform grid. Its algorithm shows full intensity even when the point covers a tiny part of the pixel. The anti-aliased version reflects that the points cover a very small part of each pixel, and it attempts to even out the error by sometimes depicting a point in one pixel and sometimes using two adjacent pixels, but dimmer. While the uniform data creates some moire effect in this contrived example, in my view the perceptual distortion is smaller.
If I make the point size much larger (e.g. 0.3), it makes for a closer match in brightness with the non-anti-aliased version. This version avoids the phantom groupings that the non-anti-aliased version has, but at the cost of the pixels looking smudged at the pixel level. That's anti-aliasing for ya.
Technical arguments aside, use the rendering method that gives you the output you want.
There is my data frame
Days,Observed,Simulated
0,0,424.8933328
1,1070,1116.781453
2,2360,2278.166227
3,3882,3854.781359
4,5712,5682.090936
5,7508,7565.230044
6,9126,9343.991798
7,10600,10919.17995
8,11893,12249.07067
9,13047,13332.93044
10,14022,14193.53941
11,14852,14863.84784
12,15480,15378.56415
13,16042,15769.6773
14,16362,16064.57556
15,16582,16285.66038
16,16766,16450.70955
17,16854,16573.54275
18,16854,16664.74816
And this is my code, hope I didn't miss out some information
dt <- read.csv('data.csv')
days <- dt$Days
Observed <- dt$Observed
Simulated <- dt$Simulated
require(ggplot2)
R <- ggplot(dt, aes(x = days))+geom_line(y=Simulated, color="red", size=0.5)+
geom_point(y=Observed, color="midnightblue", size=1.75)
a <- geom_line(aes(y = Simulated, col='Simulated'))
n <- geom_point(aes(y = Observed, fill = "Observed"), col='blue')
c <- ggtitle("2.5kg of Placenta & 0.5kg of seed")
h <- labs(x = 'Time(Days)', y = "Cumulative Biogas Yield(ml)",
colour = NULL, fill = "Legend")
o <- theme(plot.title = element_text(hjust = 0.1))+
theme( plot.title = element_text(colour = "midnightblue"),
axis.title.x = element_text(colour = "black", size = 14),
axis.title.y = element_text(colour = "black", size = 14),
legend.title = element_text(colour = "black", size = 14),
legend.text = element_text(colour = "black", size = 12.5),
axis.text.x = element_text(colour = "black", size = 14),
axis.text.y = element_text(colour = "black", size = 14))
d <- scale_color_manual(values = 'red')
s <- scale_fill_manual(values = 'midnightblue')
Myplot <- R+a+n+c+h+o+d+s
Myplot
The result I get have a big gap between the variables and needs to be removed
What I want is as follows:
I have edited the graph on the painter to get what i want but its tiresome work I would like to have the code that can easy the process for me. Thanks in advance.
You can adjust the spacing between the two legends using a combination of two theme elements: legend.spacing and legend.margin. I played around a bit with these and this combination seems to work well:
Myplot + theme(
legend.spacing = unit(0,'pt'),
legend.margin = margin(t=0,b=0,unit='pt')
)
side note
Also, just wanted to note that when you want to squish together two legends, but have one title, it is better to do it like you have (where one of the legend titles is set to NULL rather than an empty character "". NULL effectively removes the legend title as an element and makes spacing easier, whereas "" still carries the spacing of the title, even if nothing is represented. If you replace NULL with "" in your code, you'll see this... so good job with that :).
Are you just looking for theme(legend.margin)?
Myplot + theme(legend.margin = margin(0, 0, -10, 0))
I would like to use ggplot to plot a graph that looks similar to this, where the axis names (represented as the units) are shown along the axes instead of right in the middle of the axes.
The only R way I can think of is to add a text object, but that may causes alignment inconsistencies if I want to display a few similar graphs together. Editing after the figure has been produced also does not seem elegant because the same editing software's font (say ppt editors) may not look the same as the same font in R.
Is there another way to achieve this? Thanks in advance!
This is what worked for me.
library(ggplot2)
base <- ggplot(economics, aes(date, psavert)) +
geom_blank() +
labs(x="KG", y="%")
base + theme(axis.title.y = element_text(hjust = 1, size = 14), axis.title.x = element_text( hjust = 1, size = 14))
The default values for axis.title.y = element_text( hjust = .5) and axis.title.x = element_text( hjust = .5), and changing the hjust to 0 will bring the axis texts to the co-ordinate point (0,0).
Update
To replicate the background and the arrow, you can do as follows:
# see ?ggplot2::arrow
arrow <- arrow(length = unit(0.5, "cm"), ends = "last", type = "closed")
# -------------------------------------------------------------------------
# A reproducible dataset from ggplot2 (you can use your own data set)
base <- ggplot(economics, aes(date, psavert)) +
geom_blank() +
labs(x="Kg", y="%") +
theme_bw()
# -------------------------------------------------------------------------
# Add a theme layer removing boarder, grid lines and add the axes arrow
base_bg <- base + theme(
panel.border = element_blank(), panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
axis.line = element_line(arrow = arrow)
)
# -------------------------------------------------------------------------
# finally position the axis title up to the arrow
base_bg + theme(axis.title.y = element_text(hjust = 1, size = 14, face="bold", family = "TT Times New Roman"), axis.title.x = element_text( hjust = 1, size = 14, face = "bold", family="Serif"))
Output
Update - correcting % on Y-axis
#see the addition of angle = 360 on axis.title.y
base_bg + theme(axis.title.y = element_text(hjust = 1, size = 14, face="bold", family = "TT Times New Roman", angle = 360), axis.title.x = element_text( hjust = 1, size = 14, face = "bold", family="Serif"))
Output - label '%' corrected
try:
mop + theme(axis.text.x = element_text(margin=margin(1,2,3,4,"pt"),angle=0)
where 1,2,3,4 indicates the measurements of bottom, left, top, right margins
You can use hjust to move the axis label along the line, with 1 being the max.
p + theme(axis.title.x = element_text(hjust = 1), axis.title.y = element_text(hjust = 1, angle = 0))
How can I add x-axis label 'New x-lab' in the same family font to a ggplot2 object where element_blank has been used? xlab and labs does not seem to work.
library(ggplot2)
iris_p <- ggplot(iris, aes(x = Sepal.Width, y = Sepal.Length, col = Species)) +
geom_point() +
theme(axis.title = element_blank(),
text = element_text(family = 'Times'))
EDIT:
I am fully aware I can change the original code. I would like to add a lab to the object iris_p without changing the first part of the code.
Assuming iris_p is the output from some function, which you can't change directly (otherwise this seems like a rather convoluted exercise), you can add another theme() component to the plot, specifying the full element_text() for axis.title.x:
# I'm referencing the default theme_grey parameters here
iris_p +
theme(axis.title.x = element_text(family = "Times", face = "plain",
colour = "black", size = 11, lineheight = 0.9,
hjust = 0.5, vjust = 0.5, angle = 0,
margin = margin(), debug = FALSE)) +
xlab("some x axis label")
You can use element_blank() partially on the graphic.
For that, you can just specify theme(axis.title.y= element_blank()), then the x.axis can be renamed in a normal way
I want to place the title inside the plot instead at the default top position.
Here is a simple code snippet
library(ggplot2)
df <- data.frame(x = c(1:10), y = rnorm(10, 1, 2))
ggplot(df, aes(x, y))+
geom_line() +
ggtitle("Demo") +
theme(plot.title = element_text(vjust = -3))
In the past I was able to do this by varying vjust value, but now it is not working. Any idea how to do this?
In the ggplot issue "vjust not working in v 2.0 for plot.title?", Hadley writes:
"All text elements now have a margin, which by default scale with the font
size in the theme. This leads to nicer spacing, particularly at large font
sizes. This means hacks with vjust and hjust no longer work. Instead,
use the margin() parameter of element_text()"
Play around with the t and b arguments in margin to adjust the title, e.g.:
ggplot(df, aes(x, y))+
geom_line() +
ggtitle("Demo") +
theme(plot.title = element_text(margin = margin(t = 10, b = -20)))
See ?margin for further arguments.
Note that you should use the margin argument for axis.title.x and axis.title.y as well:
ggplot() + ggtitle("this is title") + xlab("this is x") + ylab("this is y") +
theme(plot.title = element_text(margin = margin(b = -10)),
axis.title.x = element_text(margin = margin(t = -10)),
axis.title.y = element_text(margin = margin(r = -10)))