finding the bounding box of plotted text - r

I would like to jitter the text on a plot so as to avoid overplotting. To do so, I assume that I need a bounding box around the text component. Is there a way to get this?
For example, in base graphics:
plot.new()
text(.5,.5,"word")
text(.6,.5,"word") #does this overlap?
In grid there is a way to drop overlapping text, but I can't seem to find a way to access the code that figures out if overlapping has occurred.
grid.text(c("word","other word"),c(.5,.6),c(.5,.5),check=T)

Maybe the strwidth and strheight functions can help here
stroverlap <- function(x1,y1,s1, x2,y2,s2) {
sh1 <- strheight(s1)
sw1 <- strwidth(s1)
sh2 <- strheight(s2)
sw2 <- strwidth(s2)
overlap <- FALSE
if (x1<x2)
overlap <- x1 + sw1 > x2
else
overlap <- x2 + sw2 > x1
if (y1<y2)
overlap <- overlap && (y1 +sh1>y2)
else
overlap <- overlap && (y2+sh2>y1)
return(overlap)
}
stroverlap(.5,.5,"word", .6,.5, "word")

Package maptools has a function called pointLabel.
Use optimization routines to find good
locations for point labels without
overlaps.

If you were using base graphics it would be thigmophobe {plotrix}
"Find the direction away from the closest point"
Using lattice, Harrell has offered:
labcurve {Hmisc}
"Label Curves, Make Keys, and Interactively Draw Points and Curves"

Related

R rasterVis levelplot: a white line erroneously appears

I am plotting maps of atmospheric pollutant fields, or meteorological field, difference between such fields, often overlayed with orography.
My fields are gridded.
A white line misteriously appears, sometimes two.
This seems to happen a bit randomly. I mean: same code and fields, same line; but when I change fields, or color scales, it changes position, or it disappears, or another one appears. Sometimes horizontal, sometimes vertical.
Here is my code
#!/usr/bin/env Rscript
library(rasterVis)
library(RColorBrewer)
NX <- 468
NY <- 421
hgt <- matrix(0.,NX,NY)
# read from file:
ucon <- file("hgt.dat", open="rb")
for (n in seq(1,NX)) {
hgt[n,] <- readBin(ucon, "numeric", n=NY, size=4)
}
close(ucon)
hgtbks <- c(-100,10,500,1000,1500,2000,2500,3000,3500)
hgtcols <- colorRampPalette(c("gray30","white"))(length(hgtbks)-1)
tit <- "Orography"
bkstart=50.0; bkmax=1500.; bkby=100.
bks <- seq(bkstart, bkmax, bkby)
nbks <- length(bks)
cols <- rev(colorRampPalette(brewer.pal(11,"Spectral"))(nbks-2))
cols <- c("white",cols)
legendbreaks <- seq(1,nbks)
legendlabels <- formatC(bks,digits=3)
legendlabpos <- legendbreaks
rpl <-
levelplot(hgt, margin=FALSE , col.regions= hgtcols, at= hgtbks
, main= list(label=tit, cex=1.8)
, colorkey=list(draw= TRUE, col=cols, at=legendbreaks
, labels=list(labels=legendlabels, at=legendlabpos, cex=1.2))
, xlab=NULL, ylab=NULL, scales= list(draw= FALSE))
png("whiteline.png", width=800, height=840)
plot(rpl)
graphics.off()
I would really like to upload a file with my data, but for the moment
I could not find a way to do it (I don't think I can do it, not even an ASCII file). The data matrix (468x421) is too big to be explicitly included in the code, but it really is the orography file
shown in the picture (elevation in meters above mean sea level).
And here is the resulting "white line" map:
Really, I think this might be a levelplot bug. It seems to happen both when hgt is a matrix and when it is a proper raster object: this doesn't seem to make a difference.
Any idea?
I think I found a workaround.
By setting zero padding on the 4 sides, I managed to make the whiteline disappear from a series of maps.
First I defined:
zpadding <- list(layout.heights= list(top.padding=0, bottom.padding=0),
layout.widths= list(left.padding=0, right.padding=0))
then I added, among the parameters of the levelplot call:
par.settings=zpadding
As I said, I don't think this is a proper solution, but a workaround.
The problem seems related to any rescaling of the plot area.
In fact, when a rescaling is forced by, for example, having 4 or 5 digits (instead of 2 or 3) in the colorbar labels, a white line may reappear.
I hope this may point in the right direction other people, either users or developers of levelplot and related software.

Bar plot with Y-axis break [duplicate]

I found a lot of SO question and answers addressing break and gaps in axis. But most of them are of low quality (in an SO meaning) because of no example code, no picture or to complex codes. This is why I asking.
I try to use library(plotrix). If there is a solution without it and/or another library it would be ok for me, too.
This is a normal R-barplot.
barplot(c(10,20,500))
To break the axis and add gap I tried this.
gap.barplot(c(10,20,500),gap=c(50,400), col=FALSE)
The result is not beautiful.
There is no space between the bars. space parameter from barplot() is not accepted by gap.barplot().
The bars have different widths.
The position of the tics are not in the middle of the bar.
Can I control that parameters with plotrix? I don't see something about it in the documentation.
Is there another library or solution for my problem?
There are so many different answers because of a lot of individual problems. For your problem you can try the following. But there is always a better solution out there. And IMO its always better to show your complete data instead of cropping it.
# Your data with names
library(plotrix)
d <- c(10,20,500)
names(d) <- letters[1:3]
# Specify a cutoff where the y.axis should be splitted.
co <- 200
# Now cut off this area in your data.
d[d > co] <- d[d > co] - co
# Create new axis label using the pretty() function
newy <- pretty(d)
newy[ newy > co] <- newy[ newy > co] + co
# remove values in your cutoff.
gr <- which(newy != co)
newy <- newy[ gr ]
# plot the data
barplot(d, axes=F)
# add the axis
axis(2, at = pretty(d)[gr], labels = newy)
axis.break(2, co, style = "gap")
As an alternative you can try to log your axis using log="y".

How to break axis in a barplot (maybe using plotrix gap.barplot)?

I found a lot of SO question and answers addressing break and gaps in axis. But most of them are of low quality (in an SO meaning) because of no example code, no picture or to complex codes. This is why I asking.
I try to use library(plotrix). If there is a solution without it and/or another library it would be ok for me, too.
This is a normal R-barplot.
barplot(c(10,20,500))
To break the axis and add gap I tried this.
gap.barplot(c(10,20,500),gap=c(50,400), col=FALSE)
The result is not beautiful.
There is no space between the bars. space parameter from barplot() is not accepted by gap.barplot().
The bars have different widths.
The position of the tics are not in the middle of the bar.
Can I control that parameters with plotrix? I don't see something about it in the documentation.
Is there another library or solution for my problem?
There are so many different answers because of a lot of individual problems. For your problem you can try the following. But there is always a better solution out there. And IMO its always better to show your complete data instead of cropping it.
# Your data with names
library(plotrix)
d <- c(10,20,500)
names(d) <- letters[1:3]
# Specify a cutoff where the y.axis should be splitted.
co <- 200
# Now cut off this area in your data.
d[d > co] <- d[d > co] - co
# Create new axis label using the pretty() function
newy <- pretty(d)
newy[ newy > co] <- newy[ newy > co] + co
# remove values in your cutoff.
gr <- which(newy != co)
newy <- newy[ gr ]
# plot the data
barplot(d, axes=F)
# add the axis
axis(2, at = pretty(d)[gr], labels = newy)
axis.break(2, co, style = "gap")
As an alternative you can try to log your axis using log="y".

Stretch x-axis between two values

I have to plot several IR-spectrums. The x-axis with this plots has to be stretched between 2000 and 500. I've tried axis(side=1,at=c(4000,3500,2000,1500,1000,500)), but this does not produce the same distance between the labels. I've searched nearly 2 hours but can't figure out how to achieve this.
Help would be appreciated.
Thanks in advance
I don't think that there's a particularly clean way to do this in base graphics - no doubt there's something in one of the many graphics packages that would do it, but heres' my workaround for what I think you're trying to do.
#Some data to plot
x <- 0:4000
y <- sin(x/100)
#A function to do the stretching that you describe
stretcher <- function(x)
{
lower <- 500 ##lower end of expansion
upper <- 2000 ##upper end of expansion
stretchfactor <- 3 ##must be greater than 1, factor of expansion
x[x>upper] <- x[x>upper] + (stretchfactor-1) * (upper-lower)
x[x<=upper & x>lower] <- (x[x<=upper & x>lower] - lower) * stretchfactor + lower
x
}
#Create the plot
plot(stretcher(x),y,axes=FALSE)
labels <- c(4000,3500,3000,2500,2000,1500,1000,500)
box()
axis(2)
axis(1,labels=labels,at=stretcher(labels))
I'd also emphasis the breaks with something like:
abline(v=stretcher(2000),col='red',lty=2)
abline(v=stretcher(500),col='red',lty=2)

Concentric Circles like a grid, centered at origin

I would like to include a sequence of concentric circles as a grid in a plot of points. The goal is to give the viewer an idea of which points in the plot have approximately the same magnitude.
I created a hack to do this:
add_circle_grid <- function(g,ncirc = 10){
gb <- ggplot_build(g)
xl <- gb$panel$ranges[[1]]$x.range
yl <- gb$panel$ranges[[1]]$y.range
rmax = sqrt(max(xl)^2+max(yl)^2)
theta=seq(from=0,by=.01,to=2*pi)
for(n in 1:ncirc){
r <- n*rmax/ncirc
circle <- data.frame(x=r*sin(theta),y=r*cos(theta))
g<- g+geom_path(data=circle,aes(x=x,y=y),alpha=.2)
}
return(g+xlim(xl)+ylim(yl))
}
xy<-data.frame(x=rnorm(100),y=rnorm(100))
ggplot(xy,aes(x,y))+geom_point()
ggg<-add_circle_grid(ggplot(xy,aes(x,y))+geom_point())
print(ggg)
But I was wondering if there is a more ggplot way to do this. I also considered using polar coordinates but it does not allow me to set x- and y-limits in the same way.
Finally, I wouldn't mind little text labels indicating the radius of each circle.
EDIT
Perhaps this is asking too much but there are two other things that I would like.
The axis limits should stay the same (which can be done via ggplot_build)
Can this work with facets? As far as I can tell you would need to somehow figure out the facets if I want to add the circles dynamically.
set.seed(1)
xy <- data.frame(x=rnorm(100),y=rnorm(100))
rmax = sqrt(max(xy$x)^2+max(xy$y)^2)
theta=seq(from=0,by=.01,to=2*pi)
ncirc=10
dat.circ = do.call(rbind,
lapply(seq_len(ncirc),function(n){
r <- n*rmax/ncirc
data.frame(x=r*sin(theta),y=r*cos(theta),r=round(r,2))
}))
rr <- unique(dat.circ$r)
dat.text=data.frame(x=rr*cos(30),y=rr*sin(30),label=rr)
library(ggplot2)
ggplot(xy,aes(x,y))+
geom_point() +
geom_path(data=dat.circ,alpha=.2,aes(group=factor(r))) +
geom_text(data=dat.text,aes(label=rr),vjust=-1)
How about this with ggplot2 and grid:
require(ggplot2)
require(grid)
x<-(runif(100)-0.5)*4
y<-(runif(100)-0.5)*4
circ_rads<-seq(0.25,2,0.25)
qplot(x,y)+
lapply(circ_rads,FUN=function(x)annotation_custom(circleGrob(gp=gpar(fill="transparent",color="black")),-x,x,-x,x))+
geom_text(aes(x=0,y=circ_rads+0.1,label=circ_rads)) + coord_fixed(ratio = 1)

Resources