I am using the radial.plot function of the plotrix-package in R. Does anyone know of a straightforward way to implement standard-error bars. The solution would have to work even when there is more than one datapoint per radial position which could lead to partial overlap of the SE-bar (see graph below).
Now the graph looks like this:
Used Code:
library(plotrix)
ppp <- matrix(runif(1:16, 10, 60), nrow=2, ncol=8)
kl <- c(0, pi/4, pi/2, pi*0.75,pi, pi+pi/4,pi+pi/2, pi+pi*0.75)
plot_rt_soa7 <- radial.plot(ppp,rp.type="p",radial.pos=kl,
label.pos=kl,start=pi/2,
labels=1:8,radial.lim=c(-10,65),main="SOA 7")
legend(45,50,c("T-oben", "T-unten"),col=1:2,lty=1)
The errorbars could look e.g. like this:
(from How to plot error bars in polar coordinates in python?)
Any help would be much appreciated
Here is some basic code that will plot error bars for both the 'x' (orthogonal to radius) and 'y' (parallel to radius) dimensions, and a point for the center value. It does not use the plotrix package for the error bar plotting, but instead uses R base graphics. You must provide the errors for the dimensions or comment out the part of the code that plots undesired errors. There are several graphical parameters for line weight, color, point color, and point shape. A sample graph is provided below.
library(plotrix)
set.seed(10) # seed for reproducable graph
ppp <- matrix(runif(1:16, 10, 60), nrow=2, ncol=8)
kl <- c(0, pi/4, pi/2, pi*0.75,pi, pi+pi/4,pi+pi/2, pi+pi*0.75)
start <- pi/2 # know starting value for plotting points angularl
rad_low_lim <- -10 # used when computing values of the error lines and in plot limits
plot_rt_soa7 <- radial.plot(ppp,rp.type="p"
,radial.pos=kl
,label.pos=kl
,start=start
,labels=1:8
,radial.lim=c(rad_low_lim,65)
,main="SOA 7")
legend(40,120,c("T-oben", "T-unten"),col=1:2,lty=1)
# generating random error values for both x and y
error_ppp_y <- matrix(rnorm(16, 15, 5), nrow=2, ncol=8)
error_ppp_x <- matrix(rnorm(16, 10, 3), nrow=2, ncol=8)
bar_cols <- c('blue','green') # colors for bars
lwds <- c(4,2) # line weights for bars
pts_cols <- c('black','red') # colors for points
pts_pch <- c(19,17) # point pch
# loop over the number of rows (T-oben and T-unten)
for(j in 1:2){
# loop over the observations
for(i in 1:ncol(ppp)){
# plotting the errors of the 'y' value
# center value is determined and errors are rotated to make
# parallel to the radius
lines(c(ppp[j,i]+error_ppp_y[j,i]-rad_low_lim,ppp[j,i]-error_ppp_y[j,i]-rad_low_lim)*cos(kl[i]+start)
,c(ppp[j,i]+error_ppp_y[j,i]-rad_low_lim,ppp[j,i]-error_ppp_y[j,i]-rad_low_lim)*sin(kl[i]+start)
,lwd=lwds[j]
,col=bar_cols[j]
)
# plotting the 'x' errors that are orthognal to the radius
# points are the "center" with the error values rotated to make them orthognal to the radius
# comment out if not desired
lines((ppp[j,i]-rad_low_lim)*cos(kl[i]+start)+c(error_ppp_x[j,i],-error_ppp_x[j,i])*cos(kl[i])
,(ppp[j,i]-rad_low_lim)*sin(kl[i]+start)+c(error_ppp_x[j,i],-error_ppp_x[j,i])*sin(kl[i])
,lwd=lwds[j]
,col=bar_cols[j]
)
# plotting points for the center
# comment out if not desired
points((ppp[j,i]-rad_low_lim)*cos(kl[i]+start)
,(ppp[j,i]-rad_low_lim)*sin(kl[i]+start)
,col=pts_cols[j]
,pch=pts_pch[j]
)
}
}
Related
The heatmap when scaling before plotting:
mat_scaled <- scale(t(mat))
pheatmap(t(mat_scaled), show_rownames=F, show_colnames=F,
border_color=F, color=colorRampPalette(brewer.pal(6,name="PuOr"))(12))
with the scale going from [-2, 6] is completely different than when using the scaling within the pheatmap function
pheatmap(t(mat_scaled), scale="row", show_rownames=F,
show_colnames=F, border_color=F, color=colorRampPalette(brewer.pal(6,name="PuOr"))(12))
where the scale is set from [-6,6].
Why is this difference and how could I obtain the matrix represented in the second figure?
In the second figure you plot the heatmap of the scaled matrix mat_scaled scaled a second time using the option scale="row" of pheatmap.
This is not the right way to compare external and internal scaling.
Here is the solution:
library(gridExtra)
library(pheatmap)
library(RColorBrewer)
cols <- colorRampPalette(brewer.pal(6,name="PuOr"))(12)
brks <- seq(-3,3,length.out=12)
data(attitude)
mat <- as.matrix(attitude)
# Scale by row
mat_scaled <- t(scale(t(mat)))
p1 <- pheatmap(mat_scaled, show_rownames=F, show_colnames=F,
breaks=brks, border_color=F, color=cols)
p2 <- pheatmap(mat, scale="row", show_rownames=F, show_colnames=F,
breaks=brks, border_color=F, color=cols)
grid.arrange(grobs=list(p1$gtable, p2$gtable))
I'm trying to plot a temporal social network in R. My approach is to create a master graph and layout for all nodes. Then, I will subset the graph based on a series of vertex id's. However, when I do this and layout the graph, I get completely different node locations. I think I'm either subsetting the layout matrix incorrectly. I can't locate where my issue is because I've done some smaller matrix subsets and everything seems to work fine.
I have some example code and an image of the issue in the network plots.
library(igraph)
# make graph
g <- barabasi.game(25)
# make graph and set some aestetics
set.seed(123)
l <- layout_nicely(g)
V(g)$size <- rescale(degree(g), c(5, 20))
V(g)$shape <- 'none'
V(g)$label.cex <- .75
V(g)$label.color <- 'black'
E(g)$arrow.size = .1
# plot graph
dev.off()
par(mfrow = c(1,2),
mar = c(1,1,5,1))
plot(g, layout = l,
main = 'Entire\ngraph')
# use index & induced subgraph
v_ids <- sample(1:25, 15, F)
sub_l <- l[v_ids, c(1,2)]
sub_g <- induced_subgraph(g, v_ids)
# plot second graph
plot(sub_g, layout = sub_l,
main = 'Sub\ngraph')
The vertices in the second plot should match layout of those in the first.
Unfortunately, you set the random seed after you generated the graph,
so we cannot exactly reproduce your result. I will use the same code but
with set.seed before the graph generation. This makes the result look
different than yours, but will be reproducible.
When I run your code, I do not see exactly the same problem as you are
showing.
Your code (with set.seed moved and scales added)
library(igraph)
library(scales) # for rescale function
# make graph
set.seed(123)
g <- barabasi.game(25)
# make graph and set some aestetics
l <- layout_nicely(g)
V(g)$size <- rescale(degree(g), c(5, 20))
V(g)$shape <- 'none'
V(g)$label.cex <- .75
V(g)$label.color <- 'black'
E(g)$arrow.size = .1
## V(g)$names = 1:25
# plot graph
dev.off()
par(mfrow = c(1,2),
mar = c(1,1,5,1))
plot(g, layout = l,
main = 'Entire\ngraph')
# use index & induced subgraph
v_ids <- sort(sample(1:25, 15, F))
sub_l <- l[v_ids, c(1,2)]
sub_g <- induced_subgraph(g, v_ids)
# plot second graph
plot(sub_g, layout = sub_l,
main = 'Sub\ngraph', vertex.label=V(sub_g)$names)
When I run your code, both graphs have nodes in the same
positions. That is not what I see in the graph in your question.
I suggest that you run just this code and see if you don't get
the same result (nodes in the same positions in both graphs).
The only difference between the two graphs in my version is the
node labels. When you take the subgraph, it renumbers the nodes
from 1 to 15 so the labels on the nodes disagree. You can fix
this by storing the node labels in the graph before taking the
subgraph. Specifically, add V(g)$names = 1:25 immediately after
your statement E(g)$arrow.size = .1. Then run the whole thing
again, starting at set.seed(123). This will preserve the
original numbering as the node labels.
The graph looks slightly different because the new, sub-graph
does not take up all of the space and so is stretched to use
up the empty space.
Possible fast way around: draw the same graph, but color nodes and vertices that you dont need in color of your background. Depending on your purposes it can suit you.
I need to use black and white color for my boxplots in R. I would like to colorfill the boxplot with lines and dots. For an example:
I imagine ggplot2 could do that but I can't find any way to do it.
Thank you in advance for your help!
I thought this was a great question and pondered if it was possible to do this in base R and to obtain the checkered look. So I put together some code that relies on boxplot.stats and polygon (which can draw angled lines). Here's the solution, which is really not ready for primetime, but is a solution that could be tinkered with to make more general.
boxpattern <-
function(y, xcenter, boxwidth, angle=NULL, angle.density=10, ...) {
# draw an individual box
bstats <- boxplot.stats(y)
bxmin <- bstats$stats[1]
bxq2 <- bstats$stats[2]
bxmedian <- bstats$stats[3]
bxq4 <- bstats$stats[4]
bxmax <- bstats$stats[5]
bleft <- xcenter-(boxwidth/2)
bright <- xcenter+(boxwidth/2)
# boxplot
polygon(c(bleft,bright,bright,bleft,bleft),
c(bxq2,bxq2,bxq4,bxq4,bxq2), angle=angle[1], density=angle.density)
polygon(c(bleft,bright,bright,bleft,bleft),
c(bxq2,bxq2,bxq4,bxq4,bxq2), angle=angle[2], density=angle.density)
# lines
segments(bleft,bxmedian,bright,bxmedian,lwd=3) # median
segments(bleft,bxmin,bright,bxmin,lwd=1) # min
segments(xcenter,bxmin,xcenter,bxq2,lwd=1)
segments(bleft,bxmax,bright,bxmax,lwd=1) # max
segments(xcenter,bxq4,xcenter,bxmax,lwd=1)
# outliers
if(length(bstats$out)>0){
for(i in 1:length(bstats$out))
points(xcenter,bstats$out[i])
}
}
drawboxplots <- function(y, x, boxwidth=1, angle=NULL, ...){
# figure out all the boxes and start the plot
groups <- split(y,as.factor(x))
len <- length(groups)
bxylim <- c((min(y)-0.04*abs(min(y))),(max(y)+0.04*max(y)))
xcenters <- seq(1,max(2,(len*(1.4))),length.out=len)
if(is.null(angle)){
angle <- seq(-90,75,length.out=len)
angle <- lapply(angle,function(x) c(x,x))
}
else if(!length(angle)==len)
stop("angle must be a vector or list of two-element vectors")
else if(!is.list(angle))
angle <- lapply(angle,function(x) c(x,x))
# draw plot area
plot(0, xlim=c(.97*(min(xcenters)-1), 1.04*(max(xcenters)+1)),
ylim=bxylim,
xlab="", xaxt="n",
ylab=names(y),
col="white", las=1)
axis(1, at=xcenters, labels=names(groups))
# draw boxplots
plots <- mapply(boxpattern, y=groups, xcenter=xcenters,
boxwidth=boxwidth, angle=angle, ...)
}
Some examples in action:
mydat <- data.frame(y=c(rnorm(200,1,4),rnorm(200,2,2)),
x=sort(rep(1:2,200)))
drawboxplots(mydat$y, mydat$x)
mydat <- data.frame(y=c(rnorm(200,1,4),rnorm(200,2,2),
rnorm(200,3,3),rnorm(400,-2,8)),
x=sort(rep(1:5,200)))
drawboxplots(mydat$y, mydat$x)
drawboxplots(mydat$y, mydat$x, boxwidth=.5, angle.density=30)
drawboxplots(mydat$y, mydat$x, # specify list of two-element angle parameters
angle=list(c(0,0),c(90,90),c(45,45),c(45,-45),c(0,90)))
EDIT: I wanted to add that one could also obtain dots as a fill by basically drawing a pattern of dots, then covering them a "donut"-shaped polygon, like so:
x <- rep(1:10,10)
y <- sort(x)
plot(y~x, xlim=c(0,11), ylim=c(0,11), pch=20)
outerbox.x <- c(2.5,0.5,10.5,10.5,0.5,0.5,2.5,7.5,7.5,2.5)
outerbox.y <- c(2.5,0.5,0.5,10.5,10.5,0.5,2.5,2.5,7.5,7.5)
polygon(outerbox.x,outerbox.y, col="white", border="white") # donut
polygon(c(2.5,2.5,7.5,7.5,2.5),c(2.5,2.5,2.5,7.5,7.5)) # inner box
But mixing that with angled lines in a single plotting function would be a bit difficult, and is generally a bit more challenging, but it starts to get you there.
I think it is hard to do this with ggplot2 since it dont use shading polygon(gris limitatipn). But you can use shading line feature in base plot, paramtered by density and angle arguments in some plot functions ( ploygon, barplot,..).
The problem that boxplot don't use this feature. So I hack it , or rather I hack bxp internally used by boxplot. The hack consist in adding 2 arguments (angle and density) to bxp function and add them internally in the call of xypolygon function ( This occurs in 2 lines).
my.bxp <- function (all.bxp.argument,angle,density, ...) {
.....#### bxp code
xypolygon(xx, yy, lty = boxlty[i], lwd = boxlwd[i],
border = boxcol[i],angle[i],density[i])
.......## bxp code after
xypolygon(xx, yy, lty = "blank", col = boxfill[i],angle[i],density[i])
......
}
Here an example. It should be noted that it is entirely the responsibility of the user to ensure
that the legend corresponds to the plot. So I add some code to rearrange the legend an the boxplot code.
require(stats)
set.seed(753)
(bx.p <- boxplot(split(rt(100, 4), gl(5, 20))))
layout(matrix(c(1,2),nrow=1),
width=c(4,1))
angles=c(60,30,40,50,60)
densities=c(50,30,40,50,30)
par(mar=c(5,4,4,0)) #Get rid of the margin on the right side
my.bxp(bx.p,angle=angles,density=densities)
par(mar=c(5,0,4,2)) #No margin on the left side
plot(c(0,1),type="n", axes=F, xlab="", ylab="")
legend("top", paste("region", 1:5),
angle=angles,density=densities)
Im drawing a knn-classification plot in R using plot to plot the samples and contour to plot the lines that classify the plane.
Here is my code:
k<-1
datax<-rbind(matrix(rnorm(30,-1,5.25),15,2),matrix(rnorm(36,1,5.25),18,2))
datay<-rbind(matrix(1,15,1),matrix(0,18,1))
plot(datax[,1], datax[,2],pch = datay+1,axes=FALSE,ann=FALSE)
box()
n <- 1000
xp <- seq(length=n, from = min(datax[,1]), to = max(datax[,1]))
yp <- seq(length=n,from = min(datax[,2]) ,to = max(datax[,2]))
gr <- expand.grid(xp, yp)
library(class)
z <- as.numeric(knn(datax, gr, datay,k))-1
zM <- matrix(z, n, n, byrow = FALSE)
contour(xp, yp, zM, xlab="x",ylab="",nlevels = 1 ,lwd=2, add=TRUE, drawlabels =FALSE)
My question is: How can i color the enclosed areas in the plot? I tried filled.contour but there is no add parameter. I simply want the area where the classifier is = 0 white and where it classifies = 1 in blue. How should i do this?
thanks
Instead of contour, you can use contourLines to keep the coordinates of the edges of the contour lines and plot them with polygon.
plot(datax[,1], datax[,2],axes=FALSE,ann=FALSE, type="n")
box()
cL <- contourLines(xp, yp, zM,nlevels = 1)
lapply(cL,function(x)polygon(x$x,x$y,col="red"))
points(datax[,1], datax[,2],pch = datay+1)
However it is not perfect with contour lines that reach the edges of the plot (see the left lower corner of the second plot), so it will need some hand-made tuning:
Edit: In the case of nested contour lines, I don't think there is an easy way to deal with it but here is one way:
library(splancs)
ord <- sapply(lapply(cL,function(x)datay[inout(datax,cbind(x$x,x$y))]),
median) #Check what values are present in the polygon and
#take the most common one
plot(datax[,1], datax[,2],axes=FALSE,ann=FALSE, type="n")
box()
lapply(cL[ord==1],function(x)polygon(x$x,x$y,col="blue"))
lapply(cL[ord==0],function(x)polygon(x$x,x$y,col="white"))
points(datax[,1], datax[,2],pch = datay+1)
2nd Edit: There is of course also the possibility of using function image in your case:
image(xp, yp, zM, col=c("transparent","blue"))
points(datax[,1], datax[,2],pch = datay+1)
Refer to the above plot. I have drawn the equations in excel and then shaded by hand. You can see it is not very neat. You can see there are six zones, each bounded by two or more equations. What is the easiest way to draw inequalities and shade the regions using hatched patterns ?
To build up on #agstudy's answer, here's a quick-and-dirty way to represent inequalities in R:
plot(NA,xlim=c(0,1),ylim=c(0,1), xaxs="i",yaxs="i") # Empty plot
a <- curve(x^2, add = TRUE) # First curve
b <- curve(2*x^2-0.2, add = TRUE) # Second curve
names(a) <- c('xA','yA')
names(b) <- c('xB','yB')
with(as.list(c(b,a)),{
id <- yB<=yA
# b<a area
polygon(x = c(xB[id], rev(xA[id])),
y = c(yB[id], rev(yA[id])),
density=10, angle=0, border=NULL)
# a>b area
polygon(x = c(xB[!id], rev(xA[!id])),
y = c(yB[!id], rev(yA[!id])),
density=10, angle=90, border=NULL)
})
If the area in question is surrounded by more than 2 equations, just add more conditions:
plot(NA,xlim=c(0,1),ylim=c(0,1), xaxs="i",yaxs="i") # Empty plot
a <- curve(x^2, add = TRUE) # First curve
b <- curve(2*x^2-0.2, add = TRUE) # Second curve
d <- curve(0.5*x^2+0.2, add = TRUE) # Third curve
names(a) <- c('xA','yA')
names(b) <- c('xB','yB')
names(d) <- c('xD','yD')
with(as.list(c(a,b,d)),{
# Basically you have three conditions:
# curve a is below curve b, curve b is below curve d and curve d is above curve a
# assign to each curve coordinates the two conditions that concerns it.
idA <- yA<=yD & yA<=yB
idB <- yB>=yA & yB<=yD
idD <- yD<=yB & yD>=yA
polygon(x = c(xB[idB], xD[idD], rev(xA[idA])),
y = c(yB[idB], yD[idD], rev(yA[idA])),
density=10, angle=0, border=NULL)
})
In R, there is only limited support for fill patterns and they can only be
applied to rectangles and polygons.This is and only within the traditional graphics, no ggplot2 or lattice.
It is possible to fill a rectangle or polygon with a set of lines drawn
at a certain angle, with a specific separation between the lines. A density
argument controls the separation between the lines (in terms of lines per inch)
and an angle argument controls the angle of the lines.
here an example from the help:
plot(c(1, 9), 1:2, type = "n")
polygon(1:9, c(2,1,2,1,NA,2,1,2,1),
density = c(10, 20), angle = c(-45, 45))
EDIT
Another option is to use alpha blending to differentiate between regions. Here using #plannapus example and gridBase package to superpose polygons, you can do something like this :
library(gridBase)
vps <- baseViewports()
pushViewport(vps$figure,vps$plot)
with(as.list(c(a,b,d)),{
grid.polygon(x = xA, y = yA,gp =gpar(fill='red',lty=1,alpha=0.2))
grid.polygon(x = xB, y = yB,gp =gpar(fill='green',lty=2,alpha=0.2))
grid.polygon(x = xD, y = yD,gp =gpar(fill='blue',lty=3,alpha=0.2))
}
)
upViewport(2)
There are several submissions on the MATLAB Central File Exchange that will produce hatched plots in various ways for you.
I think a tool that will come handy for you here is gnuplot.
Take a look at the following demos:
feelbetween
statistics
some tricks