Define plot elements size in mm (R) - r

I am preparing figures in R for submission to a journal. Required formatting is given in mm (line width = 0.5mm, symbols = 3mm, etc).
I know how to define the figure size in mm, and to manage line width and symbol size with respectively lwd and cex, either in par() or within the plot function. I also found how to convert points to mm. However I don't know how to define line weight, text size, etc. precisely, and not "scaling up" as usual (eg. I want lwd = 0.5mm, not lwd = 1.2 x the default size).
I hope I am clear enough =)
Here is my code :
jpeg(paste('path-to-figure.jpg'), width=15, height=7)
plot(x, y, main = 'TITLE', xlab = "X NAME",ylab = 'Y NAME', ylim = c(0,180), xlim = c(0, 4)pch = 1)
dev.off()
Many Thanks !

Line widths in the standard jpeg, png etc. graphics devices are defined in 1/96 of an inch. See https://stat.ethz.ch/R-manual/R-devel/library/grDevices/html/png.html . The same is true for pdf but may vary for other devices. 0.5 mm = 0.5 / 25.4 * 96 = 1.890 96ths of an inch. So you would use lwd = 1.89.
You could also consider using ggplot2 since size within that is in mm anyway.
E.g.
ggplot(my_data, aes(x, y)) + geom_line(size = 0.5)

Related

How to adjust the y-axis of bar plot in R using only the barplot function

Using this example:
x<-mtcars;
barplot(x$mpg);
you get a graph that is a lot of barplots from (0 - 30).
My question is how can you adjust it so that the y axis is (10-30) with a split at the bottom indicating that there was data below the cut off?
Specifically, I want to do this in base R program using only the barplot function and not functions from plotrix (unlike the suggests already provided). Is this possible?
This is not recommended. It is generally considered bad practice to chop off the bottoms of bars. However, if you look at ?barplot, it has a ylim argument which can be combined with xpd = FALSE (which turns on "clipping") to chop off the bottom of the bars.
barplot(mtcars$mpg, ylim = c(10, 30), xpd = FALSE)
Also note that you should be careful here. I followed your question and used 0 and 30 as the y-bounds, but the maximum mpg is 33.9, so I also clipped the top of the 4 bars that have values > 30.
The only way I know of to make a "split" in an axis is using plotrix. So, based on
Specifically, I want to do this in base R program using only the barplot function and not functions from plotrix (unlike the suggests already provided). Is this possible?
the answer is "no, this is not possible" in the sense that I think you mean. plotrix certainly does it, and it uses base R functions, so you could do it however they do it, but then you might as well use plotrix.
You can plot on top of your barplot, perhaps a horizontal dashed line (like below) could help indicate that you're breaking the commonly accepted rules of what barplots should be:
abline(h = 10.2, col = "white", lwd = 2, lty = 2)
The resulting image is below:
Edit: You could use segments to spoof an axis break, something like this:
barplot(mtcars$mpg, ylim = c(10, 30), xpd = FALSE)
xbase = -1.5
xoff = 0.5
ybase = c(10.3, 10.7)
yoff = 0
segments(x0 = xbase - xoff, x1 = xbase + xoff,
y0 = ybase-yoff, y1 = ybase + yoff, xpd = T, lwd = 2)
abline(h = mean(ybase), lwd = 2, lty = 2, col = "white")
As-is, this is pretty fragile, the xbase was adjusted by hand as it will depend on the range of your data. You could switch the barplot to xaxs = "i" and set xbase = 0 for more predictability, but why not just use plotrix which has already done all this work for you?!
ggplot In comments you said you don't like the look of ggplot. This is easily customized, e.g.:
library(ggplot2)
ggplot(x, aes(y = mpg, x = id)) +
geom_bar(stat = "identity", color = "black", fill = "gray80", width = 0.8) +
theme_classic()

Changing text size of 3d plot, R

I have a problem changing the text size of a 3d plot I generated with the package rgl. Everything works fine, but I can't effectively change the cex and size properties of an 3d object when rendering it in shiny, with the renderWebGL
library(rgl)
plot3d(x, y, z, xlab ="x", ylab ="y", zlab ="z")
texts3d(x, y, z, rownames(data))
Any help is highly appreciated! Best Regards.
Brecht
You can scale the text (including axis labels) by changing the "cex" rgl parameter, by calling the function par3d. The "cex" rgl parameter is different from the "cex" parameter in base graphics.
For example, if you want to magnify the text in your plot by a factor of 2, then you can call:
par3d(cex=2.0)
with(iris,
plot3d(Sepal.Length, Sepal.Width, Petal.Length,
type="s", col=as.numeric(Species)))
Note that calling par3d opens a plotting window. Calling a plotting function creates a plot in that same window. You have to call par3d every time you create a new plot. The function par3d can also change many other rgl parameters.
I ran into similar problems with library plot functions from PerformanceAnalytics. I would advise to get the code for the function by typing plot3d in the console and looking at the original plot functions inside.
It might be the case that the plot3d function doesn't pass a cex option forward, so you can also copy the function and modify it to make it your own myplot3d function or something like that.
For anyone still trying to address this issue, the plot3D package takes care of this nicely now.
See the following reproducible code.
# Load plot3D package
library(plot3D)
Using the iris dataset, let's make a 3D graph. See our use of cex, cex.main, and cex.lab at the end, which allow us to multiply text size, all within the package.
scatter3D(
x = iris$Sepal.Length,
y = iris$Sepal.Width,
z = iris$Petal.Length,
# Add a nice background
bty = "u",
col.grid = "darkgrey",
col.panel = "black",
# Specify Labels
main = "My graph",
clab = "Petal\nLength",
xlab = "\nSepal Length",
ylab = "\nSepal Width",
zlab = "\nPetal Length",
# Adjust label sizing
cex = 2, # Multiply dot size by 2
cex.main = 2, # Multiply the size of main title text by 2
cex.lab = 2) # Multiply size of axis label text by 2
Or, we can shrink the text size back to normal, here:
scatter3D(
x = iris$Sepal.Length,
y = iris$Sepal.Width,
z = iris$Petal.Length,
# Add a nice background
bty = "u",
col.grid = "darkgrey",
col.panel = "black",
# Specify Labels
main = "My graph",
clab = "Petal\nLength",
xlab = "\nSepal Length",
ylab = "\nSepal Width",
zlab = "\nPetal Length",
# Adjust label sizing
cex = 1, # Multiply dot size by 2
cex.main = 1, # Multiply the size of main title text by 2
cex.lab = 1) # Multiply size of axis label text by 2
Not the OP situation but if you need to change the text size on a rgl plot and your text is a LaTeX expression you have to pass the text size parameter (cex) to the corresponding function.
For example,
library(rgl)
library(magrittr)
iris %>%
{points3d('x'=.$Sepal.Length, 'y'=.$Sepal.Width, z=.$Petal.Length)}
title3d(main=NULL, sub=setName,
xlab=latex2exp::TeX(r"($\phi_{\pi})"),
ylab=latex2exp::TeX(r"($\phi_{X}$)"),
zlab=latex2exp::TeX(r"($\psi_{B}$)"),
cex=4)
Notice the cex argument in title3d() which is passed to plotmath3d() which actually draws the LaTeX expression into a PNG file that is then paste on the final plot. See the documentation for plotmath3d for details but cex is a number that scales the text size.

R legend issue, symbols of points are masked by lines

Is there a way to draw the lines in such a way that they would start on the side of the points, or allow the symbols to be in foreground?
My solution was to make the symbols bigger and more visible.
Edit 1: it's for plot {graphics} of the R program.
Edit 2: the code per popular request.
legend(2,.4,bty='n', c('sugar','citrus','none'), pch=c('s','c','u'), pt.bg='white',lty= c(1,2,3), lwd=1.5, title="Condition",pt.cex=c(1.5),cex=1.5)
Edit 3: This is solved for plot(type='b') but somehow not for legend.
Thanks for reading!
The only thing I can come up with is to manually finagle the dash lengths until they end up looking the way you want them. For instance, this:
> plot(1,1)
> legend(c("A", "B"), col = 1:2, x = 1, y = .8, lty="99", pch=1:2)
produces the image below.
The lty parameter allows you to specify the lengths of lines and dashes as hex characters. In this case, it's saying to create a line of length 9 then create a space of length 9 then repeat. It looks like 9 is about the best fit to space around a normal pch symbol.
Note that you'd probably need to adjust this depending on the size of the image, symbol, etc. My advice ultimately would be to export the image from R and touch up the image to meet your needs in graphic editing software.
Going with the suggestion by #JeffAllen, here is a way to get what I think you might want. It requires modifying the legend() function to return the position of the points (these are given by x1 and y1 in body(legend)[[46]]).
legend2 <- legend
body(legend2)[[49]] <- quote(
invisible(list(rect = list(w = w, h = h, left = left, top = top),
text = list(x = xt, y = yt), points = list(x = x1, y = y1)))
)
Make a plot:
plot(-100:100, -100:100, type = "b")
While drawing the legend, draw white circles (pch = 21 with pt.bg = 'white') over the lines, and assign the values invisibly returned by legend2() to an object. Note also the changes to pt.lwd and pt.cex.
myLegend <- legend2(1, .8, bty = 'n', c('sugar','citrus','none'), pch = 21,
pt.bg = 'white', pt.lwd = 0, lty = c(1, 2, 3), lwd = 1.5, title = "Condition",
pt.cex = c(1.8), cex = 1.5)
Finally, draw the characters you'd like to use in the legend using points(), supplying the x and y values from the object myLegend.
points(myLegend$points$x, myLegend$points$y, pch = c('s','c','u'), cex = 1.5)
And this should get you something like:
You could also use the filled points offered by R (pch=21:25) and specify the fill color using pc.bg which gets passed to the points call when creating a legend.
plot(1,1)
legend(c("A", "B"), col = 1:2, x = 1, y = .8, lty=1, pt.bg=1:2, pch=21:22)
generates the following:

GNU R, VennDiagram, and making a complement diagram

I have been working on Venn Diagrams in GNU R. I have tried using the packages venneuler and VennDiagram. I find that VennDiagram has a lot more granular control, but it seems to lack the documentation to fill in all the details. The closest I can find is this PPT file.
http://www.ncbi.nlm.nih.gov/pmc/articles/PMC3041657/bin/1471-2105-12-35-S4.PPT which I found from the URL: http://www.ncbi.nlm.nih.gov/pmc/articles/PMC3041657/
Here are my issues with using VennDiagram.
For the code
require(VennDiagram)
venn.diagram(list(B = 1:2000, A = 200:400),fill = c("yellow", "blue"),
alpha = c(0.8, 0.8), cex =1.5, cat.pos=0, cat.fontface = 4,
lty = 1, fontfamily =3, filename = "test001.jpeg");
(I had an image here, but since I am new I do not have rights to post the image. Please generate the image from the code above.)
I can make a subset (hence a circle within a circle). But I am not finding a way to do the following:
Make BC to show as the equal of B^C. No, a literal "B^C" does not work. I would think there is a way to relabel the sets in a different property, but I have not seen a way to do it.
To position the labels of B^C and A^C within the sets and not on the outside as currently shown. I tried cat.pos="inner" but that way not a valid property. I also tried cat.pos=c(0,0) in the hope that I could feed it as an X,Y where X & Y are from the center of the circle, but it did not produce any different results.
Thanks to DWin, here is the code to complete my diagram to the exercise.
Suppose that A ⊂ B. Show that Bc ⊂ Ac.
require(VennDiagram)
plot.new()
venn.plot <- venn.diagram(
x = list(B = 1:200, A = 20:40), category.names= expression(B, A),
fill = c("yellow", "blue"), alpha = c(0.8, 0.8), cex =1.5,
cat.pos=0, cat.dist=c(-.1, -.1), filename = NULL) ;
grid.draw(venn.plot); # grid graphic requires explicit print or draw operation
grid.text(expression(B^c),x=0.2,y=0.95)
grid.text(expression(A^c),x=0.16,y=0.95)
grid.text(expression(A^c),x=0.16,y=0.75)
Perhaps something like this:
venn.diagram(list(B = 1:200, A = 20:40), category.names= expression(B^c, A),
fill = c("yellow", "blue"), alpha = c(0.8, 0.8), cex =1.5, cat.pos=0,
cat.dist=c(.1, -.1), cat.fontface = 4,lty = 1, fontfamily =3,
filename = "test001.jpeg")
To get the labels inside the circles, supply 'cat.dist' with negative values. The trick is that the reference point is radial distance from the boundary at 12 o'clock rather than from the center. The documentation says that the category.names argument is interpreted with plotmath syntax. The superscript operation in plotmath is done with the "^" operator. I have here moved the A" inside while leaving the B^c outside to suggest that it is the area outside the B circle that is being labeled. (I also improved the plotting time by making the example smaller.) I tried drawing three labels but that does not seem to "part of the package".
Here's a way you can annotate with grid.text() on the screen device:
plot.new()
venn.plot <- venn.diagram(
x = list(B = 1:200, A = 20:40), category.names= expression(B^c, A),
fill = c("yellow", "blue"), alpha = c(0.8, 0.8), cex =1.5,
cat.pos=0, cat.dist=c(.05, -.1), filename = NULL) ;
grid.draw(venn.plot); # grid graphic requires explicit print or draw operation
grid.text("B",x=0.8)
# then you can save to file

R plot: size and resolution

I have stacked into the question: I need to plot the image with DPI=1200 and specific print size.
By default the png looks ok...
png("test.png",width=3.25,height=3.25,units="in",res=1200)
par(mar=c(5,5,2,2),xaxs = "i",yaxs = "i",cex.axis=1.3,cex.lab=1.4)
plot(perf,avg="vertical",spread.estimate="stddev",col="black",lty=3, lwd=3)
dev.off()
But when I apply this code, the image became really terrible it's not scaling (fit) to the size that is needed. What did I miss? How to "fit" the image to the plot?
,
A reproducible example:
the_plot <- function()
{
x <- seq(0, 1, length.out = 100)
y <- pbeta(x, 1, 10)
plot(
x,
y,
xlab = "False Positive Rate",
ylab = "Average true positive rate",
type = "l"
)
}
James's suggestion of using pointsize, in combination with the various cex parameters, can produce reasonable results.
png(
"test.png",
width = 3.25,
height = 3.25,
units = "in",
res = 1200,
pointsize = 4
)
par(
mar = c(5, 5, 2, 2),
xaxs = "i",
yaxs = "i",
cex.axis = 2,
cex.lab = 2
)
the_plot()
dev.off()
Of course the better solution is to abandon this fiddling with base graphics and use a system that will handle the resolution scaling for you. For example,
library(ggplot2)
ggplot_alternative <- function()
{
the_data <- data.frame(
x <- seq(0, 1, length.out = 100),
y = pbeta(x, 1, 10)
)
ggplot(the_data, aes(x, y)) +
geom_line() +
xlab("False Positive Rate") +
ylab("Average true positive rate") +
coord_cartesian(0:1, 0:1)
}
ggsave(
"ggtest.png",
ggplot_alternative(),
width = 3.25,
height = 3.25,
dpi = 1200
)
If you'd like to use base graphics, you may have a look at this. An extract:
You can correct this with the res= argument to png, which specifies the number of pixels per inch. The smaller this number, the larger the plot area in inches, and the smaller the text relative to the graph itself.
An alternate solution to lowering the size of the various components with pointsize and the cex functions is to increase the size of the graph to compensate. This maintains the scale by increasing the size of everything instead of only some components. Your graph will be larger when exported, but will retain the improved resolution if manually decreased in size should you wish to retain the original smaller size.
The png default settings are dpi=72, height=480, width=480. So to maintain the same scale, you need to multiply height and width by the resolution/72. Using your example of width = height = 3.25 inches and a desired resolution dpi of 1200, we will adjust by 1200/72 (equal to 50/3):
reso <- 1200
length <- 3.25*reso/72
png("test.png",units="in",res=reso,height=length,width=length)
par(mar=c(5,5,2,2),xaxs = "i",yaxs = "i",cex.axis=1.3,cex.lab=1.4)
plot(perf,avg="vertical",spread.estimate="stddev",col="black",lty=3, lwd=3)
dev.off()

Resources