Controlling addLines - r

I have an xts object (NCGSpot) I use for charting and would like to add a vertical line on a given date to the plot. Here is what I do:
chartSeries(NCGSpot, TA="addBBands();addLines()", subset="2015-04-02::2016-08-01",theme="white")
How can I control where the Lines is drawn. I have seen stuff like
addLines(v=anynumber)
But I cannot make much sense out of it and could not find any information on it.
Its there any way I pass on a date to addLines and get the line on that date?
Thx in advance

If you use chart_Series, (better charting capabilities than chartSeries) you can create vertical lines from scratch using an xts object containing a matrix type of logical, where TRUE applies to the dates where vertical lines are desired. The argument on should be set to 1 or -1 if you want the vertical lines on your main chart. Setting -1 will put the lines behind the candles. Other useful parameters included col and border (should be self explanatory). Here is an example to get you started:
library(quantmod)
getSymbols("AAPL")
xt <- xts(rep(FALSE, NROW(AAPL)), index(AAPL))
dates_for_vertical_marks <- c("2016-02-01", "2016-04-29")
xt[dates_for_vertical_marks, ] <- TRUE
xt2 <- xts(rep(FALSE, NROW(AAPL)), index(AAPL))
dates_for_vertical_marks <- c("2016-07-01")
xt2[dates_for_vertical_marks, ] <- TRUE
chart_Series(AAPL, subset="2016")
add_TA(xt, on =-1, col= "orange", border='blue')
add_TA(xt2, on = 1, col= "darkgreen", border='darkgreen')

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.

Controlling margins in a genoPlotR plot_gene_map

I'm producing a plot_gene_map figure by the genoPlotR R package, which gives a horizontal phylogenetic tree where aligned with each leaf is a genomic segment.
Here's a simple example that illustrates my usage and problem:
The plot_gene_map function requires an ade4s' package phylog object which represents the phylogenetic tree:
tree <- ade4::newick2phylog("(((A:0.08,B:0.075):0.028,(C:0.06,D:0.06):0.05):0.0055,E:0.1);")
A list of genoPlotR's dna_seg objects (which are essentially data.frames with specific columns), where the names of the list elements have to match the names of the leaves of tree:
dna.segs.list <- list(A=genoPlotR::as.dna_seg(data.frame(name=paste0("VERY.LONG.NAME.A.",1:10),start=seq(1,91,10),end=seq(5,95,10),strand=1,col="black",ly=1,lwd=1,pch=1,cex=1,gene_type="blocks",fill="red")),
B=genoPlotR::as.dna_seg(data.frame(name=paste0("VERY.LONG.NAME.B.",1:10),start=seq(1,91,10),end=seq(5,95,10),strand=1,col="black",ly=1,lwd=1,pch=1,cex=1,gene_type="blocks",fill="blue")),
C=genoPlotR::as.dna_seg(data.frame(name=paste0("VERY.LONG.NAME.C.",1:10),start=seq(1,91,10),end=seq(5,95,10),strand=1,col="black",ly=1,lwd=1,pch=1,cex=1,gene_type="blocks",fill="green")),
D=genoPlotR::as.dna_seg(data.frame(name=paste0("VERY.LONG.NAME.D.",1:10),start=seq(1,91,10),end=seq(5,95,10),strand=1,col="black",ly=1,lwd=1,pch=1,cex=1,gene_type="blocks",fill="yellow")),
E=genoPlotR::as.dna_seg(data.frame(name=paste0("VERY.LONG.NAME.E.",1:10),start=seq(1,91,10),end=seq(5,95,10),strand=1,col="black",ly=1,lwd=1,pch=1,cex=1,gene_type="blocks",fill="orange")))
And a list of genoPlotR's annotation objects, which give coordinate information, also named according to the tree leaves:
annotation.list <- lapply(1:5,function(s){
mids <- genoPlotR::middle(dna.segs.list[[s]])
return(genoPlotR::annotation(x1=mids,x2=NA,text=dna.segs.list[[s]]$name,rot=30,col="black"))
})
names(annotation.list) <- names(dna.segs.list)
And the call to the function is:
genoPlotR::plot_gene_map(dna_segs=dna.segs.list,tree=tree,tree_width=2,annotations=annotation.list,annotation_height=1.3,annotation_cex=0.9,scale=F,dna_seg_scale=F)
Which gives:
As you can see the top and right box (gene) names get cut off.
I tried playing with pdf's width and height, when saving the figure to a file, and with the margins through par's mar, but they have no effect.
Any idea how to display this plot without getting the names cut off?
Currently genoPlotR's plot_gene_map does not have a legend option implemented. Any idea how can I add a legend, let's say which shows these colors in squares aside these labels:
data.frame(label = c("A","B","C","D","E"), color = c("red","blue","green","yellow","orange"))
Glad that you like genoPlotR.
There are no real elegant solution to your problem, but here are a few things you can attempt:
- increase annotation_height and reduce annotation_cex
- increase rotation (“rot”) in the annotation function
- use xlims to artificially increase the length of the dna_seg (but that’s a bad hack)
For the rest (including the legend), you’ll have to use grid and its viewports.
A blend of the first 3 solutions:
annotation.list <- lapply(1:5,function(s){
mids <- genoPlotR::middle(dna.segs.list[[s]])
return(genoPlotR::annotation(x1=mids, x2=NA, text=dna.segs.list[[s]]$name,rot=75,col="black"))
})
names(annotation.list) <- names(dna.segs.list)
genoPlotR::plot_gene_map(dna_segs=dna.segs.list,tree=tree,tree_width=2,annotations=annotation.list,annotation_height=5,annotation_cex=0.4,scale=F,dna_seg_scale=F, xlims=rep(list(c(0,110)),5))
For the better solution with grid: (note the "plot_new=FALSE" in the call to plot_gene_map)
# changing rot to 30
annotation.list <- lapply(1:5,function(s){
mids <- genoPlotR::middle(dna.segs.list[[s]])
return(genoPlotR::annotation(x1=mids,x2=NA,text=dna.segs.list[[s]]$name,rot=30,col="black"))
})
names(annotation.list) <- names(dna.segs.list)
# main viewport: two columns, relative widths 1 and 0.3
pushViewport(viewport(layout=grid.layout(1,2, widths=unit(c(1, 0.3), rep("null", 2))), name="overall_vp"))
# viewport with gene_map
pushViewport(viewport(layout.pos.col=1, name="geneMap"))
genoPlotR::plot_gene_map(dna_segs=dna.segs.list,tree=tree,tree_width=2,annotations=annotation.list,annotation_height=3,annotation_cex=0.5,scale=F,dna_seg_scale=F, plot_new=FALSE)
upViewport()
# another viewport for the margin/legend
pushViewport(viewport(layout.pos.col=2, name="legend"))
plotLegend(…)
upViewport()
Hope that helps!
Lionel
Which function or package could I use to add the legend? The R base functions did not seem to work for me. The following message is displayed:
Error in strheight(legend, units = "user", cex = cex) :
plot.new has not been called yet"

Change of col argument throwing an error and how to store individual graphical parameters

I'll try to define my companies colors and fonts etc to all the plots we're doing. So first question: How can I store them without overwriting the "normal" par settings? I mean can I store all in a "par-Container" and give them to each plot etc?
Ok here I defined the Colors:
GRAPH_BLUE<-rgb(43/255, 71/255,153/255)
GRAPH_ORANGE<-rgb(243/255, 112/255, 33/255)
GRAPH_BACKGROUND<-rgb(180/255, 226/255, 244/255)
If I do plot(something, col=GRAPH_BLUE) I get the error:
Error in axis(1, at = xycoords$x, labels = FALSE, col = "#BBBBBB", ...) :
formal argument "col" matched by multiple actual arguments
If I do par(col=GRAPH_BLUE) and plot(something) it works exactly as I want. Why is that? What would I need to change that it works in the first line of code? As I understand it throws the error since there are multiple settings starting with col and with plot(something, col=GRAPH_BLUE) I overwrite all of them and that's why the axis isn't visible. But is there a special col setting for just the color line of the chart?
EDIT: Ok here's a reproducible example:
getSymbols('SPY', from='1998-01-01', to='2011-07-31', adjust=T)
GRAPH_BLUE<-rgb(43/255, 71/255,153/255)
GRAPH_ORANGE<-rgb(243/255, 112/255, 33/255)
GRAPH_BACKGROUND<-rgb(180/255, 226/255, 244/255)
par(col=GRAPH_BLUE)
plot.xts(SPY) #works great
plot.xts(SPY, col=GRAPH_ORANGE) #not really since all axes are missing
And the first question is if I could store all these Settings not directly in par() but in another variable which I pass to the plot function?
No there isn't a special col setting for just the color line of the chart. You should use par or modify the code source of the function and add it like the case of bar.col or candle.col. I don't know why they do it for types bar and candle and not for lines? I guess to not have a lot of parameters...
Note the you can save the old parameters of par every time you change it.
op <- par(col=GRAPH_BLUE)
... ## some plot job
par(op) ## retsore it
It easy also to hack the function and add a new col parameters for lines. Only few lines to change in the function:
plot.xts.col <- function (old.parameters,lines.col='green', ...) {
.....
## you change this line to add the paremeter explicitly
plot(xycoords$x, xycoords$y, type = type, axes = FALSE,
ann = FALSE,col=lines.col, ...)
## and the last line since .xtsEnv is an internal object
assign(".plot.xts", recordPlot(), xts:::.xtsEnv)
}

R axis text no dots

I want to add the following x-axis label to my bar plot but unfortunately R does not recognize the character '!' and prints dots instead of whitespaces:
I want: I get:
!src x.x.x.x X.src.x.x.x.x
!TCP X.TCP
!udp && !src x.x.x.x X.udp.....src.x.x.x.x
Additionally a would like to increase the margin because the text is to long and when setting the size over 'cex.names=0.6' then it just vanishes!?
There are two reason I can think of that R will have substituted X. for instances of !.
I suspect that the labelling you are seeing is due to R's reading of your data. Those column names aren't really syntactically valid and the erroneous character has been replaced by X.. This happens at the data import stage, so I presume you didn't check how R had read your data in?, or
You have a vector and the names of that vector are similarly invalid and R has done the conversion.
However, as you haven't made this reproducible it could be anything.
To deal with case 1 above, either edit your data file to contain valid names or pass check.names = FALSE in your read.table() call used to read in the data. Although doing the latter will make it difficult for you to select variable by name without quoting the name fully.
If you have a vector, then you can reset the names again:
> vec <- 1:5
> names(vec) <- paste0("!",LETTERS[1:5])
> vec
!A !B !C !D !E
1 2 3 4 5
> barplot(vec)
Also note that barplot() has a names.arg argument that you can use to pass it the labels to draw beneath each bar. For example:
> barplot(vec, names.arg = paste0("!", letters[1:5]))
which means you don't need to rely on what R has read in/converted for you as you tell it exactly what to label the plot with.
To increase the size of the margin, there are several ways to specify the size but I find setting it in terms of number of lines most useful. You change this via graphical parameter mar, which has the defaults c(5,4,4,2) + 0.1 which correspond to the bottom, left, top, and right margins respectively. Use par() to change the defaults, for example in the code below the defaults are store in op and a much larger bottom margin specified
op <- par(mar = c(10,4,4,2) + 0.1)
barplot(vec, names.arg = paste0("!", letters[1:5]), las = 2)
par(op) ## reset
The las = 2 will rotate the bar labels 90 degrees to be perpendicular to the axis.
One option is to use ann=F and add anotation to the plot using mtext.
x <- 1:2
y <- runif(2, 0, 100)
par(mar=c(4, 4, 2, 4))
plot(x, y, type="l", xlim=c(0.5, 2.5), ylim=c(-10, 110),
axes=TRUE, ann=FALSE)
Then add annotation:
mtext("!udp && !src x.x.x.x ", side=1, line=2)
Edit It is a question of a barplot and not simple plot.
as said in Gavin solution, the names argument can be setted. Here I show an example.
barplot(VADeaths[1:2,], angle = c(45, 135),
density = 20, col = "grey",
names=c("!src x.x.x.x", "!TCP", "!udp && !src x.x.x.x", "UF"),
horiz=FALSE)

How to draw lines on a plot in R?

I need to draw lines from the data stored in a text file.
So far I am able only to draw points on a graph and i would like to have them as lines (line graph).
Here's the code:
pupil_data <- read.table("C:/a1t_left_test.dat", header=T, sep="\t")
max_y <- max(pupil_data$PupilLeft)
plot(NA,NA,xlim=c(0,length(pupil_data$PupilLeft)), ylim=c(2,max_y));
for (i in 1:(length(pupil_data$PupilLeft) - 1))
{
points(i, y = pupil_data$PupilLeft[i], type = "o", col = "red", cex = 0.5, lwd = 2.0)
}
Please help me change this line of code:
points(i, y = pupil_data$PupilLeft[i], type = "o", col = "red")
to draw lines from the data.
Here is the data in the file:
PupilLeft
3.553479
3.539469
3.527239
3.613131
3.649437
3.632779
3.614373
3.605981
3.595985
3.630766
3.590724
3.626535
3.62386
3.619688
3.595711
3.627841
3.623596
3.650569
3.64876
By default, R will plot a single vector as the y coordinates, and use a sequence for the x coordinates. So to make the plot you are after, all you need is:
plot(pupil_data$PupilLeft, type = "o")
You haven't provided any example data, but you can see this with the built-in iris data set:
plot(iris[,1], type = "o")
This does in fact plot the points as lines. If you are actually getting points without lines, you'll need to provide a working example with your data to figure out why.
EDIT:
Your original code doesn't work because of the loop. You are in effect asking R to plot a line connecting a single point to itself each time through the loop. The next time through the loop R doesn't know that there are other points that you want connected; if it did, this would break the intended use of points, which is to add points/lines to an existing plot.
Of course, the line connecting a point to itself doesn't really make sense, and so it isn't plotted (or is plotted too small to see, same result).
Your example is most easily done without a loop:
PupilLeft <- c(3.553479 ,3.539469 ,3.527239 ,3.613131 ,3.649437 ,3.632779 ,3.614373
,3.605981 ,3.595985 ,3.630766 ,3.590724 ,3.626535 ,3.62386 ,3.619688
,3.595711 ,3.627841 ,3.623596 ,3.650569 ,3.64876)
plot(PupilLeft, type = 'o')
If you really do need to use a loop, then the coding becomes more involved. One approach would be to use a closure:
makeaddpoint <- function(firstpoint){
## firstpoint is the y value of the first point in the series
lastpt <- firstpoint
lastptind <- 1
addpoint <- function(nextpt, ...){
pts <- rbind(c(lastptind, lastpt), c(lastptind + 1, nextpt))
points(pts, ... )
lastpt <<- nextpt
lastptind <<- lastptind + 1
}
return(addpoint)
}
myaddpoint <- makeaddpoint(PupilLeft[1])
plot(NA,NA,xlim=c(0,length(PupilLeft)), ylim=c(2,max(PupilLeft)))
for (i in 2:(length(PupilLeft)))
{
myaddpoint(PupilLeft[i], type = "o")
}
You can then wrap the myaddpoint call in the for loop with whatever testing you need to decide whether or not you will actually plot that point. The function returned by makeaddpoint will keep track of the plot indexing for you.
This is normal programming for Lisp-like languages. If you find it confusing you can do this without a closure, but you'll need to handle incrementing the index and storing the previous point value 'manually' in your loop.
There is a strong aversion among experienced R coders to using for-loops when not really needed. This is an example of a loop-less use of a vectorized function named segments that takes 4 vectors as arguments: x0,y0, x1,y1
npups <-length(pupil_data$PupilLeft)
segments(1:(npups-1), pupil_data$PupilLeft[-npups], # the starting points
2:npups, pupil_data$PupilLeft[-1] ) # the ending points

Resources