Plotting half circles in R - r

I'm trying to plot half circles using R. My final aim is to draw a circle, divided in the middle by color. The only way I have found yet is to draw two half-circles with different colors.
So I have created my own functions:
upper.half.circle <- function(x,y,r,nsteps=100,...){
rs <- seq(0,pi,len=nsteps)
xc <- x+r*cos(rs)
yc <- y+r*sin(rs)
polygon(xc,yc,...)
}
lower.half.circle <- function(x,y,r,nsteps=100,...){
rs <- seq(0,pi,len=nsteps)
xc <- x-r*cos(rs)
yc <- y-r*sin(rs)
polygon(xc,yc,...)
}
However, for some reason my half-circles end up more like half-ellipses. For example, try running:
plot(1, type="n",axes=F,xlab="", ylab="",xlim=c(0,200),ylim=c(0,200))
upper.half.circle(15,170,10,nsteps=1000,col='red')
Does anyone know why I'm having this trouble, or alternatively, knows of a better way to do what I want?
Thanks!

The problem is the default aspect ratio is not 1:1.
To fix this, set asp=1 in plot:
Inspired by this Q & A. You could have sniffed out this was the case by turning on the axes and x/y labels.

If using the grid package would be also an opportunity for you, there is a much simpler solution:
library(grid)
vp <- viewport(width=0.5, height=0.5, clip = "on")
grid.circle(0.5,0,r=0.5, gp = gpar(fill = 'red'), vp = vp)
This creates a viewport with clipping, i.e., an appropriate positioning of the filled circle creates a half circle.

If you want to add your half circles to an existing plot (and therefore cannot control the aspect ratio directly) then one option for this specific case is to use the floating.pie function from the plotrix package.
A more general tool for creating custom symbols and adding them to plots (with the symbols having a different aspect ratio from the overall plot) is to use the my.symbols function from the TeachingDemos package.

Related

How to draw circles around polygon/spider chart, without plotting libraries

Without using ggplot2 or other plotting libraries, I would need to draw circles around a polygon/star chart vertices, i.e. each circle with a radius equal to the respective polygon radius. You can see an example here:
d1 <- 1:4
names(d1) <- LETTERS[1:4]
stars(matrix(d1,nrow=1),axes=TRUE, scale=FALSE,radius=TRUE, frame.plot=TRUE,labels = dimnames(d1)[[1]])
grid()[enter image description here][1]
I understand I should combine the stars() with the symbols(), polygon() functions or par(...) graphics, but honestly, I am new to these kind of plotting techniques and very lost on how to combine functions and arguments
I don't know of any functions in base R that do circles for you, but you can concoct them manually.
center <- c(x=2.1, y=2.1) # probably a better way
half <- seq(0, pi, length.out = 51)
for (D in d1) {
Xs <- D * cos(half); Ys <- D * sin(half)
lines(center["x"] + Xs, center["y"] + Ys, col = "gray", xpd = NA)
lines(center["x"] + Xs, center["y"] - Ys, col = "gray", xpd = NA)
}
Notes:
I don't know off-hand how the center-point should be calculated, I chose that point using locator(1); not being familiar with stars, there may be a better way to determine this programmatically and more accurately;
The first lines(.) draws the upper semi-circle; the second draws the lower.
The xpd=NA is to preclude clipping due to the drawing margin. It may not be necessary in your "real" data. See ?par for more details on this.
Though it may be difficult to detect here, the gray circles are drawn on top of the stars plot, which might be an aesthetic compromise. The only way around that is to plot the circles first. To do this, draw the first semicircle first with plot(..., type="l") and then add the remainder as expected, and only then run stars(..., add=TRUE).

Add legend in igraph to annotate difference vertices size

I have a graph in igraph with a vertex size that is coded for a value.
I wish to add a legend with symbols (points in my case) with different sizes.
I tried the following code
require(igraph)
er_graph <- erdos.renyi.game(100, 5/100)
value<-runif(100)
n<-6
size_vec<-seq_len(n)
sizeCut<-cut(value,n)
vertex.size<-size_vec[sizeCut]
plot(er_graph, vertex.label=NA, vertex.size=vertex.size)
legend('topleft',legend=levels(sizeCut),pt.cex=size_vec,col='black')
but end with legend without symbols
see example
Any sugestions how I go about this?
You should set pch to some value to indicate which character you want to use for the bullets (see ?points to check the possible values).
Also, you should scale the pt.cex values in order to make the bullets not too big for the legend, and use pt.bg to set the background color of the bullets, e.g.
# scaled between 1 and 2
scaled <- 1 + ((2-1) * (size_vec - min(size_vec) ) / ( max(size_vec) - min(size_vec) ) )
legend('topleft',legend=levels(sizeCut),pt.cex=scaled,col='black',pch=21, pt.bg='orange')
EDIT :
Unfortunately, calculating the right sizes of the bullets is not easy; a possible workaround is plotting white bullets then manually add the vertices to the legend in the same way they are plotted inside the plot.igraph function :
# N.B. /200 is taken from plot.igraph source code
a <- legend('topleft',legend=levels(sizeCut),pt.cex=size_vec/200,col='white',
pch=21, pt.bg='white')
x <- (a$text$x + a$rect$left) / 2
y <- a$text$y
symbols(x,y,circles=size_vec/200,inches=FALSE,add=TRUE,bg='orange')
Disclaimer: this code heavily relies on the source code of plot.igraph function that might be changed in a future version of igraph. Probably you should search for another plot function for igraph which natively allows to add a legend.
Anyone looking at this who wants a continuous scale for node sizes instead of a discrete scale then this is the code you need to do it:
require(igraph)
er_graph <- erdos.renyi.game(100, 5/100)
value<-runif(100)
sizeCut<- c(0.2,0.4,0.6,0.8,1.0)
sizeCutScale <- sizeCut*10
vertex.size<-value*10
plot(er_graph, vertex.label=NA, vertex.size=vertex.size)
legend('topleft',legend=unique(sizeCut),pt.cex= sizeCutScale,col='black')
a <- legend('topleft',legend=unique(sizeCut),pt.cex=sizeCutScale/200,col='white',
pch=21, pt.bg='white')
x <- (a$text$x + a$rect$left) / 2
y <- a$text$y
symbols(x,y,circles=sizeCutScale/200,inches=FALSE,add=TRUE,bg='orange')

Exporting graphs in R

I have two graphs that I plotted in R and I want to export it as a high-resolution picture for publication.
For example:
a<-c(1,2,3,4,5,6,7)
b<-c(2,3,4,6,7,8,9)
par(mfrow=c(2,1))
plot (a,b)
plot(a,b)
I usually export this graph by:
dev.copy(jpeg,'test.jpeg',width=80,height=150,units="mm",res=200)
dev.off()
However I always find this process a bit troublesome. The graph that was plotted in R does not necessarily look like the one that I exported. Therefore, I am wondering if there is a way to specifiy the dimensions and resolution of graphs before I plot them so that I can visually inspect the graphs before I export them?
Thank you
You can try:
png('out.png')
a<-c(1,2,3,4,5,6,7)
b<-c(2,3,4,6,7,8,9)
par(mfrow=c(2,1))
plot (a,b)
plot(a,b)
dev.off()
As baptiste said, jpeg is the worst format you can choose. You should take a look at the help for the bmp and png functions (with ?bmp and ?png). Both bmp and png have height, width, and res arguments that you can use to specifiy the dimensions and resolution of the output. Also, I wouldn't recommend the use of dev.copy. As you could see, the result of the output is not always what you expect.
To add to Bonifacio2's answer, you if you call the function first to make the plot, you can also define your margins and window size etc before doing any actual plotting. That way you have full control over all fig specs.
pdf(file='test.jpeg',width=80,height=150,units="mm") #I prefer pdf, because they are editable files
a<-c(1,2,3,4,5,6,7)
b<-c(2,3,4,6,7,8,9)
par(mfrow=c(2,1))
plot (a,b)
plot(a,b)
dev.off()
You can use cowplot package to combine multiple panels in several different ways. For example, in your case, we export one plot with two panels arranged in two rows and one column. I assume that you prefer to use base-R 'plot' function instead of ggplot.
library(cowplot)
p1 <- ~{
plot(a,b)
}
p2 <- ~{
plot(b,a)
}
png("plot.png",
width = 3.149606, # 80 mm
height = 5.905512, # 150 mm
units = 'in',
res = 500)
plot_grid(p1, p2, labels = "AUTO", nrow = 2, ncol = 1)
dev.off()
Note that you can either remove the labels if not needed or print small letters by using "auto". Regarding size of the text, axis-labels etc, use the standard arguments for generic plot function of base-R. I hope this answer helps you. Best wishes.

Change ylab position in R Scatterplot3D

I´m working with R scatterplot3D and I need to use expression() in labels because I have to use some Greek letters;
my question is: is there a way to pull the y.lab name down or write it along the axis (in a diagonal position)? I went to help and packages description but nothing seems to work;
thanks in advance for any help
Maria
library(scatterplot3d)
par(mfrow=c(1,1))
A <- c(3,2,3,3,2)
B <- c(2,4,5,3,4)
D <- c(4,3,4,2,3)
scatterplot3d(A,D,B, xlab=expression(paste(x[a],"-",x[b])),
ylab=expression(x[a]),
zlab=expression(sigma^2))
You can't use any of the classic ways due to the way the scatterplot3d() function constructs the plot. It's basically plotted on top of a classic plot pane, which means the axis labels are bound to the classic positions. The z-label is printed at the real left Y-axis, and the y label is printed at the real right Y-axis.
You can use text() to get around this:
use par("usr") to get the limits of the X and Y coordinates
calculate the position you want the label on (at 90% of the horizontal position and 8% of the vertical position for example.)
use text() to place it (and possibly the parameter srt to turn the label)
This makes it a bit more generic, so you don't have try different values for every new plot you make.
Example :
scatterplot3d(A,D,B, xlab=expression(paste(x[a],"-",x[b])),
ylab="",
zlab=expression(sigma^2))
dims <- par("usr")
x <- dims[1]+ 0.9*diff(dims[1:2])
y <- dims[3]+ 0.08*diff(dims[3:4])
text(x,y,expression(x[a]),srt=45)
Gives
scatterplot3d(A,D,B, xlab=expression(paste(x[a],"-",x[b])),
ylab="",
zlab=expression(sigma^2))
mtext( expression(x[a]), side=4,las=2,padj=18, line=-4)
One does need to use fairly extreme parameter values to get the expression in the right place in that transformed spatial projection.

How to get shaded background in xyplot in R?

using xyplot from the lattice package, I plot a time series over a number of years. I would to add a shaded area for some of these years to indicate that this time period was "special" (e.g. war).
Please apologize if this is trivial, but I could not figure out how to do that, so I would be happy if someone could help me out, or at least point me in the right direction. I think my main problem is that I don't really know how to approach this problem. I am still relatively new to R, and to lattice in particular.
Here a minimal example:
xyplot( rnorm(100) ~ 1:100, type="l", col="black")
In the corresponding plot, I would like the color of the background (from say x-values of 45 until 65) from the bottom to the top of the plotting area be shaded in, say, light grey.
Note that solutions that I have found so far use base graphics and the polygon-function, but there the intention is to shade the area under or above a curve, which is different from what I would like to do. I don't "just" want to shade the area below my line, or above my line. Instead I would like to shade the entire background for a given time interval.
If anyone could help me out here, I would be very grateful!
See ?panel.xblocks in the latticeExtra package:
library(latticeExtra)
x <- 1:100
xyplot( rnorm(100) ~ x, type="l", col="black") +
layer_(panel.xblocks(x, x > 20, col = "lightgrey"))
Try this:
xyplot(
rnorm(100) ~ 1:100, type="l", col="black",
panel=function (x,y,...){
panel.rect(xleft=45, xright=65,ybottom=-3, ytop=3,col="grey")
panel.xyplot(x,y,...)
}
)
The panel.rect() function controls the rectangle and is the lattice equivalent of the rect() function. It has a variety of settings that you may find useful. It is called first and then the xyplot() is put on top of it. You many need to play around a little to get your ybottom and ytop parameters to look as you like them.
trellis.focus("panel", 1, 1)
grid.rect(x =.55, , y=.5, w = .2, height=6,
gp = gpar(fill = "light grey"))
trellis.unfocus()
This differs from #JohnPaul's solution in a couple of ways (and I think his answer is better). This uses the center of the desired X-band for placement in "native coordinates" and calculates the width as 'range(xlim)/range(band)' and it modifies an existing plot. the grid.rect function is the grid packages lower level function that is used by panel.rect. I sometimes find this useful when integrating lattice panels inside the xyplot system defeats me.

Resources