I have found R's default plots to be poorly aliased. As a solution, I set Cairo as the graphics device, and now the plots look much better.
Unfortunately, using Cairo has created another issue, which is that for some reason, I am not able to apply the font that I was using when the graph was displayed in the plot window (in the left-hand diagram above, Cambria is used, but the right-hand diagram fails to apply this font).
Here is my code:
library(readxl)
library(scales)
library(ggplot2)
library(dplyr)
library('Cairo')
windowsFonts(Cam = windowsFont("Cambria"))
dataset <- read_excel('CW Data.xlsx')
colnames(dataset)[4] <- "Broadband Subs (%)"
options(scipen = 1000)
# Scatter plot FDI~GDP with regression line
CairoWin()
ggplot(dataset, aes(x=`2019 GDP ($bn)`, y=`2019 FDI ($m)`)) +
geom_point(size=3, shape=1) +
geom_smooth(method='lm',formula=y~x, se=FALSE, color='black') +
scale_x_continuous(label = comma) + scale_y_continuous(label=comma) +
theme(panel.background = element_rect(fill="peachpuff"),
plot.background = element_rect(fill="peachpuff")) +
theme(panel.grid.major = element_line(colour = "gray72"),
panel.grid.minor = element_line(colour = "gray72")) +
theme(text = element_text(family = "Cam"))
ggsave("FDI~GDP.png", device="png", type = "cairo")
And here is a OneDrive link for the Excel data that I am using
https://1drv.ms/x/s!AvGKDeEV3LOs4gNr714Ie0KbOjhO?e=bkdPvk
I suggest you have a look at the packages ragg and systemfonts. They make working with fonts extremly easy and the results are better than the output of the base options.
First, I suggest you query all available fonts using View(systemfonts::system_fonts()). You can select every font present here and use it for plotting or saving a plot.
I recreated your plot using a built in dataset as the onedrive link you shared was broken. I used the Cambria font like this.
plot <- ggplot(dataset, aes(x = mpg, y = hp)) +
geom_point(size = 3, shape = 1) +
geom_smooth(
method = 'lm',
formula = y ~ x,
se = FALSE,
color = 'black'
) +
scale_x_continuous(label = comma) +
scale_y_continuous(label = comma) +
labs(x = "2019 GDP ($bn)", y = "2019 FDI ($m)") +
theme(
panel.background = element_rect(fill = "peachpuff"),
plot.background = element_rect(fill = "peachpuff")
) +
theme(
panel.grid.major = element_line(colour = "gray72"),
panel.grid.minor = element_line(colour = "gray72")
) +
theme(text = element_text(family = "Cambria")) # relevant line
I prefer saving the plot in an object and passing it explicitly to the save function.
ggsave(
"FDI~GDP.png",
plot = plot,
device = ragg::agg_png, # this is the relevant part
width = 1920,
height = 1080,
units = "px"
)
Here is the result:
I would say it worked flawlessly. You can also use ragg as your graphics device in RStudio to make this more consistent. Have a look here.
If you want to output the plot to a PDF, you can use showtext to register system fonts with all newly opening graphics devices. So what you need to do is:
library(showtext)
showtext_auto()
ggsave(
"FDI~GDP.pdf",
plot = plot,
width = 1920,
height = 1080,
units = "px"
)
I am trying to recreate this visualization of a bubble chart using ggplot2 (I have found the code for doing this in R, but not with the ggplot2 package). This is what I have so far. There are some other errors with my code at the moment, but I want to have the legend show concentric circles for size, versus circles shown in rows. Thanks for your help!
Original visualization:
My reproduction:
My (simplified) code:
crime <-
read.csv("http://datasets.flowingdata.com/crimeRatesByState2005.tsv",
header=TRUE, sep="\t")
ggplot(crime,
mapping= aes(x=murder, y=burglary))+
geom_point(aes(size=population), color="red")+
geom_text(aes(label=state.name), show.legend=FALSE, size=3)+
theme(legend.position = c(0.9, 0.2))
Here's an approach where we build the legend as imagined from scratch.
1) This part slightly tweaks your base chart.
Thank you for including the source data. I missed that earlier and have edited this answer to use it. I switched to a different point shape so that we can specify both outside border (color) as well as interior fill.
gg <- ggplot(crime,
mapping= aes(x=murder, y=burglary))+
geom_point(aes(size=population), shape = 21, color="white", fill = "red")+
ggrepel::geom_text_repel(aes(label = state.name),
size = 3, segment.color = NA,
point.padding = unit(0.1, "lines")) +
theme_classic() +
# This scales area to size (not radius), specifies max size, and hides legend
scale_size_area(max_size = 20, guide = FALSE)
2) Here I make another table to use for the concentric legend circles
library(dplyr); library(ggplot2)
legend_bubbles <- data.frame(
label = c("3", "20", "40m"),
size = c(3E6, 20E6, 40E6)
) %>%
mutate(radius = sqrt(size / pi))
3) This section adds the legend bubbles, text, and title.
It's not ideal, since different print sizes will require placement tweaks. But it seems like it'd get complicated to get into the underlying grobs with ggplot_build to extract and use those sizing adjustments...
gg + geom_point(data = legend_bubbles,
# The "radius/50" was trial and error. Better way?
aes(x = 8.5, y = 250 + radius/50, size = size),
shape = 21, color = "black", fill = NA) +
geom_text(data = legend_bubbles, size = 3,
aes(x = 8.5, y = 275 + 2 * radius/50, label = label)) +
annotate("text", x = 8.5, y = 450, label = "Population", fontface = "bold")
I need to export graphics from R for the use in different publications formats, i.e., scientific poster, Journal Articel, Powerpoint presentation. As Long as I'm not aware of using R-Markdown and Latex, Or Sweave to produce pdf slides, i need to use Microsoft applications.
I do graphics in R with ggplot2.
My MWE
df1 <- expand.grid(Year = c(2000, 2010),
Treat = c("TreatA","TreatB"),
Location = c("Berlin", "Munich", "Kansas", "Paris"),
rep = c(1,2,3,4,5,6,7,8,9,10))
df1 <- cbind(df1,
Var1 = runif(160, -10,25) + rnorm(160,8,4))
My Graphics Code:
p1 <- ggplot(aes(y = Var1, x = Treat, na.rm=TRUE, fill=Location), data = df1) +
stat_boxplot(geom ='errorbar', width= 0.5) +
geom_boxplot(outlier.shape = 1, outlier.size = 2, linetype="solid", size = 1) +
facet_grid( Year ~ Location) +
scale_y_continuous(limits=c(-20,60)) +
scale_fill_manual(values=c("#E69F00", "#009E73", "#0072B2", "#D55E00")) +
ylab("Magic Skills") +
xlab("Magic Juice") +
theme(text=element_text(family="Arial", size=18),
axis.text.x = element_text(angle = 30, hjust = 1),
line=element_line(size=1),
rect=element_rect(colour="red", size=1),
panel.background=element_rect(colour="black",fill="white", size=1),
strip.background=element_rect(colour="dark grey", fill="black"),
strip.text=element_text(face="bold", colour="white"),
panel.grid.major=element_blank(),
panel.grid.minor=element_blank(),
legend.position="none");p1
How I save the graph:
ggsave(p1, file="Results/Figures/Abb2_Boxplots_LarvenPuppen2.svg", width=35, height=20, units = "cm", dpi=500)
I set the font size with "theme(text=element_text(family="Arial", size=18)" for the whole graph.
During ggsave I adjust the height and width, for the Poster the height should be 20 cm and width 35 cm. I save in .svg since I made best experience with the quality of the graph, furthermore I can edit anything at anytime in Inkscape, that's great!
So far so good, yet, it appears, that the text is by no means 18 pt, later in the powerpoint-poster, after exporting the graph (without editing!) as .png from Inkscape. It is even not 20 x 35 cm, I found that i loose about 5 cm or more during the saving and export process.
I guess R is doing write, when i say save 20x35 cm R will do it. Where in the whole process were my settings changed, and how can I handle it?
Best regards,
Pharcyde
There's a few things to consider:
SVG units – Note the discussion about user units, and pt vs px
grid graphics parameters and how they're interpreted by the device
ggplot2, and how its theme settings affect the font size
Here's a pure grid example that illustrates the second point,
library(grid)
g <- grobTree(rectGrob(), textGrob("test", gp=gpar(fontsize=12)))
ggplot2::ggsave("size.svg", g, width = 10, height=10, units = "in")
tmp <- readLines("size.svg")
grep("test", tmp, value = TRUE)
# "<text x='350.33' y='364.30' style='font-size: 12.00px; font-family: Arial;' textLength='19.34px' lengthAdjust='spacingAndGlyphs'>test</text>"
grep("viewBox", tmp, value = TRUE)
# "<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' viewBox='0 0 720.00 720.00'>"
So short answer is that the svg produced by R (svglite here) contains a seemingly consistent font size (12px), but the 10 inches is interpreted as 720px regardless of dpi. Looking at the source this 72 factor comes from R graphics conventions (typically devices follow the pdf device, which defaults to a 72DPI resolution. Why this is not affected by the various dpi/res/pointsize parameters is a mystery to me).
The gridSVG package by-passes the usual graphics engine system, and appears to produce more straight-forward sizes,
library(gridSVG)
gridsvg("size.svg", res = 1000, width=10, height=5)
grid.draw(g)
dev.off()
tmp <- readLines("size.svg")
grep("viewBox", tmp, value = TRUE)
# "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"10000px\" height=\"5000px\" viewBox=\"0 0 10000 5000\" version=\"1.1\">"
though this time the font size is scaled (it is 12 for the default 72DPI resolution),
grep("font-size", tmp, value = TRUE)
# "<text x=\"0\" y=\"0\" id=\"GRID.text.41.1.1.text\" text-anchor=\"middle\" font-size=\"166.67\" fill=\"rgb(0,0,0)\" fill-opacity=\"1\">"
On the ggplot2 side, things get even murkier because of some built-in settings for the inheritance of theme elements, rel()ative scaling, scales, that may or may not be documented (and have changed in the past IIRC).
"18pt" in an SVG is not the same as 18pt on a printed page.
One point ("pt") in a CSS style attribute has been defined - like in the printing industry - as 1/72 of an inch. However in CSS, an inch is not a real-world inch, but instead it is 96 "CSS pixels".
That dpi of 96, is a arbitrary value chosen a long time ago. Computer monitors aren't 96 pixels per inch any more (if any ever were).
If you want something to match the real world - for example one real inch on a printed page or screen - you will have to test your environment and output method, and apply a scaling factor to your SVG units. Or to your conversion technique.
Here is how it worked:
p1 <- ggplot(aes(y = Var1, x = Treat, na.rm=TRUE, fill=Location), data = df1) +
stat_boxplot(geom ='errorbar', width= 0.5) +
geom_boxplot(outlier.shape = 1, outlier.size = 2, linetype="solid", size = 1) +
facet_grid( Year ~ Location) +
scale_y_continuous(limits=c(-20,60)) +
scale_fill_manual(values=c("#E69F00", "#009E73", "#0072B2", "#D55E00")) +
ylab("Magic Skills") +
xlab("Magic Juice") +
theme(text=element_text(family="Arial", size=36*96/72),
axis.text.x = element_text(angle = 30, hjust = 1),
line=element_line(size=1),
rect=element_rect(colour="red", size=1),
panel.background=element_rect(colour="black",fill="white", size=1),
strip.background=element_rect(colour="dark grey", fill="black"),
strip.text=element_text(face="bold", colour="white"),
panel.grid.major=element_blank(),
panel.grid.minor=element_blank(),
legend.position="none");p1
ggsave(p1, file="Results/Figures/Trial.svg", width=35*1.25, height=20*1.25, units="cm", dpi=96)
With this code, I got an 35x20 cm plot both in Inkscape and in Powerpoint.
Furthermore the size of the letters was pretty much the size of letters in powerpoint.
This time I chose letter size 36pt, since this is more useful for Poster-presentations. I did not make further trials with changing the dpi.
Here my findings so far:
R uses 72 dpi by default, the formula: size * new resolution DPI / 72 DPI,
e.g.: 36 * 96/72, delivers almost similar pt sizes in Microsoft office documents. Irrespective of both the dpi settings used in ggsave as well as the height and width settings.
10 cm specified in R via ggsave() correspond to 8.060 cm in Inkscape. Multiplying the admired width/height by 1.25 delivers correct image sizes in Inkscape and also in MS Office, irrespective of the dpi set in the Export settings.
Something that makes me still wonder is that although I made the same settings for font size for the WHOLE plot via "text=element_text(family="Arial", size=36*96/72)"
Label titles are taller than tick labels or text in the facet boxes.
best wishes,
Pharcyde
The font size used by ggplot matches font size in word the problem is that the figure gets resized during saving, during importing, or both. The best solution for me has been to set a graphics window to the size the figure will be in the document (5.33" x 4" usually looks good in Word; 7.5" x 10" for a 4:3 PowerPoint), and then save the figure as that size. You may need to play around with file types (.tif doesn't play nice in PowerPoint and gets resized for some reason). That said, if you use this method and be sure that the figure isn't resized after it is exported from R it will have the exact size font as you had when you made your ggplot.
Here is the code I use,
dev.new(width = 10, height = 7.5, unit="in", noRStudioGD = T);last_plot() #Set new windo size and replot whatever plot you just made.
ggsave("workingdirectory/plot.png",width = dev.size()[1],height = dev.size()[2]);dev.off() #Save the plot and set the size using `dev.siz()` so you don't have to ever change that part and cannot possibly have a typo.
And here is a full example with output that you can bring into a 4:3 PowerPoint and see for yourself that it works.
measure1<-as.numeric(1:50)
category<-rep(c("a","b","c","d","e"),each=10)
df<-data.frame(measure1,category)
library(ggplot2)
library(extrafont)
ggplot(df, aes(x = category , y = measure1, fill = category, colour = category)) +
geom_boxplot(outlier.shape = NA, show.legend = F, notch = F) +
geom_point(aes(),size = 3, shape=16, colour="white", alpha=.6) +
stat_summary(fun.y=mean, show.legend = FALSE, geom="point", shape=18, size=5, colour = "white", na.rm = TRUE) +
ylab("Measure") +
xlab("Category") +
ggtitle("") +
scale_y_continuous (limits = c(0,50), expand = c(0,0), breaks=seq(0,50,5))+
scale_x_discrete(limits=c("a","b","c","d","e")) +
scale_fill_manual(values = rep("black",5))+
scale_colour_manual(values = rep("white",5))+
theme_bw() +
theme (text=element_text(size=24, family="Times New Roman"),
axis.title.y=element_text(size=24, vjust=2, colour="white"),
axis.title.x=element_text(size=24, hjust=0.5, colour="white"),
panel.border = element_blank(),
plot.title=element_blank(),
plot.margin = unit(c(.5, .5, .5, .5), "cm"),
panel.background = element_rect(fill = "black"),
plot.background = element_rect(fill = "black"),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
legend.position = "none",
axis.ticks = element_line(size=0.8, colour = "white"),
axis.ticks.length=unit(0.2,"cm"),
axis.text.x=element_text(colour="white",size=24,angle=0,hjust=.5),
axis.text.y=element_text(colour="white",size=24),
axis.line = element_line(colour="white", size=0.8, lineend = "square"))
dev.new(width = 10, height = 7.5, unit="in", noRStudioGD = T);last_plot()
ggsave("C:/Users/s39f171/Documents/plot.png",width = dev.size()[1],height = dev.size()[2]);dev.off()