R legend pch mix of character and numeric - r

Is it possible to use a mix of character and number as plotting symbols in R legend?
plot(x=c(2,4,8),y=c(5,4,2),pch=16)
points(x=c(3,5),y=c(2,4),pch="+")
legend(7,4.5,pch=c("+",16),legend=c("A","B")) #This is the problem

Use the numerical equivalent of the "+" character:
plot(x=c(2,4,8),y=c(5,4,2),pch=16)
points(x=c(3,5),y=c(2,4),pch="+")
legend(7,4.5,pch=c(43,16),legend=c("A","B"))

There are actually numerical equivalents for all symbols!
Source: Dave Roberts
The pch code is the concatenation of the Y and X coordinates of the above plot.
For example, the + symbol is in row (Y) 4 and column (X) 3, and therefore can be drawn using pch = 43.
Example:
plot(x=c(2,4,8),y=c(5,4,2),pch=16)
points(x=c(3,5),y=c(2,4),pch="+")
legend(7,4.5,pch=c(43,16),legend=c("A","B"))

My first thought is to plot the legend twice, once to print the character symbols and once to print the numeric ones:
plot(x=c(2,4,8),y=c(5,4,2),pch=16)
points(x=c(3,5),y=c(2,4),pch="+")
legend(7,4.5,pch=c(NA,16),legend=c("A","B")) # NA means don't plot pt. character
legend(7,4.5,pch=c("+",NA),legend=c("A","B"))
NOTE: Oddly, this works in R's native graphical device (on Windows) and in pdf(), but not in bmp() or png() devices ...

I bumped to this issue several time, so I wrote a tiny function below. You can use to specify the pch value, e.g.
pch=c(15:17,s2n("|"))
String to Numeric

As noted in previous answers, you can simply add the numerical equivalent of the numeric and character symbols you want to plot.
However, just a related aside: if you want to plot larger numbers (e.g., > 100) or strings (e.g., 'ABC') as symbols, you need to use a totally different approach based on using text().
`Plot(x,y,dat,type='n') ; text(x,y,labels = c(100,'ABC')
Creating a legend in this case is more complicated, and the best approach I've ever come up with is to stack legends on top of each other and using the legend argument for both the pch symbol and the description:
pchs <- c(100,'ABC','540',sum(13+200),'SO77')
plot(1:5,1:5,type='n',xlim=c(1,5.1))
text(1:5,1:5,labels = pchs)
legend(3.5,3,legend = pchs,bty='n',title = '')
legend(3.5,3,legend = paste(strrep(' ',12),'ID#',pchs),bty='n',title='Legend')
rect(xleft = 3.7, ybottom = 1.5, xright = 5.1, ytop = 3)
This uses strrep to concatenate spaces in order to shift the text over from the "symbols", and it uses rect to retroactively fit a box around the printed legend text.

Related

Bug in dotchart pch?

I think there may be a bug in the way the pch parameter is read within the dotchart function, but would appreciate peer confirmation before reporting it.
In the following, I would like both colour and symbol to vary with the group. Colour works fine, as expected, but not symbol.
foo <- data.frame(Specimen=paste("Specimen", 1:18),
Group=c(rep("Benign", 4),
rep("In-situ", 6),
rep("Invasive", 8)),
Outcome=rweibull(18, 5) + (1:18 / 18))
with(foo, dotchart(Outcome,
groups = Group,
color = c("green", "orange", "red")[Group],
pch=c(16, 15, 17)[Group],
xlab="Outcome measure /bar",
labels = Specimen))
There is an easy but rather bizarre workaround by reversing the "Group" column encoding pch :
with(foo, dotchart(Outcome,
groups = Group,
color = c("green", "orange", "red")[Group],
pch=c(16, 15, 17)[rev(Group)],
xlab="Outcome measure /bar",
labels = Specimen))
However, I cannot see a single legitimate reason why the vector for pch should have to be reversed, particularly since colour seems to work entirely as expected. Thoughts?
Incidentally, the reason I generally try to vary the symbol as well as the colour for different groups in a chart is for the benefit of colour blind readers. Granted, it is not so important in this case.
I agree this may be a bug (which I am genuinely cautious about in base R functions like this).
Specficially, dotchart reorders the color and lcolor (line color) arguments here:
o <- sort.list(as.numeric(groups), decreasing = TRUE)
x <- x[o]
groups <- groups[o]
color <- rep_len(color, length(groups))[o]
lcolor <- rep_len(lcolor, length(groups))[o]
...and those are used in the subsequent abline and points calls, but pch is passed on unchanged. The fix would likely be to simply add the line,
pch <- rep_len(pch, length(groups))[o]
If I wanted to put my pedantic hat on (which is a good idea before submitting a bug report), I would note that the documentation for ?dotchart specifies:
color the color(s) to be used for points and labels.
for the color argument, but only:
pch the plotting character or symbol to be used.
for the pch argument. Some may argue that this "clearly" implies that only color is intended to take multiple values, and so in that sense this isn't a "bug".
This definitely looks like a bug. I have a dataset where samples have a fairly complex 4*4 color+pch coding corresponding to things that are also in the sample names, on top of groups, and the pch values just don't seem to be reordered at all during group reordering. I'll try to submit a bug report in the next weeks. I have R 3.6.1

Color option in xtsExtra

I am having trouble adjusting the colors of a multiple time series plot using xtsExtra.
This is the code of a minimal example:
require("xtsExtra")
n <- 50
data <- replicate(2, rnorm(n))
my.ts <- as.xts(ts(data, start=Sys.Date()-n, end=Sys.Date()))
plot.zoo(my.ts, col = c('blue', 'green'))
plot.xts(my.ts, col = c('blue', 'green'))
The plot.zoo commands yields
,
whereas the plot command from the xtsExtra package results in
.
In the second plot, the two time series are nicely overlaid, but seem insensitive to the col option.
I'm using the latest version 0.0-1 of the xtsExtra package (rev. 862).
It is my understanding that the xts and xtsExtra packages are designed as extensions of zoo and should work with the same arguments (plus many additional ones). Even though I can get the same overlay behavior in plot.zoo using the screens option, I cannot really resort to using it because the call to plot.xts that causes my problems is within the quantstrat package (functions chart.forward.training and chart.forward.testing for example) which I'd loathe to modify. (Incidentally, the dev.new() in these functions is causing me trouble as well.)
Question: Why does plot from the xtsExtra package seem not to respond to the col= option and what can be done about it, if modifying
the call to the function is not a real option?
Q1. If you take time to read the help text for plot.xts, you see that the function does not have a col argument. Together with the fact that partial matching of argument names doesn't seem to be allowed in the function, it explains why plot.xts it does not respond col =.
Compare with a case where partial matching works:
plot(x = 1:2, y = 1:2, type = "b"); plot(x = 1:2, y = 1:2, ty = "b"); "ty" matches "type".
See here: "If the name of the supplied argument matches exactly with the first part of a formal argument then the two arguments are considered to be matched".
Q2. Instead you may use the colorset argument:
"color palette to use, set by default to rational choices" (colorset = 1:12).
plot.xts(my.ts, colorset = c('blue', 'green'))

Transform numbers with exponents to plotmath commands for beautiful legends in R

I'm trying to generate a beautiful legend in R plots. I have a factor=1e-5, that should appear nicely formatted in the legend. I found a nice function in the package sfsmisc, that transforms numbers to expressions. To add this expression to my bquote command, it seems that I need to transform itto a call. unfortunately, there are braces added at the end of the string (10^-5()).
Is there a way to avoid the addition of thoses braces? Or is there even an easier way to transform numbers to plotmaths commands for their use in legends? (without doing it manually)
factor = 1e-5
alpha = 1:10
omega = alpha^2 * factor
plot (
alpha
, omega
, xlab=bquote(alpha)
, ylab=bquote(omega)
, type="b"
)
text = expression()
# standard version
text[1] = as.expression(bquote(alpha%*%.(factor)))
# beautified version (use pretty10exp from sfsmisc package!?)
library("sfsmisc")
pretty = as.call(pretty10exp(factor, drop.1=T))
text[1] = as.expression(bquote(alpha^2%*%.(pretty)))
# add legend
legend("topleft", legend=text, pch=1, lty=1)
Here's what you can do instead with function parse:
text <- paste("alpha^2%*%",parse(text=pretty10exp(factor,drop.1=T)),sep="")
text
[1] "alpha^2%*%10^-5" # which we then use as the expression in your call to legend
legend("topleft", legend=parse(text=text), pch=1, lty=1)
See ?parse for more explanation on how this work.

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 add nice formated anotations to a R base graph using expression and the value of a variable?

Say, I have a variable rv which has some numerical value. Now, I want to plot the value of this variable on a base plot but preceded by a nicely formatted symbol e.g., r subscript m, using expression. To write on the plot I use mtext.
However, what I get is either the value of the variable, but no nicely formatted symbol (left annotation), or a nicely formatted symbol, but not the value of the variable, but the variable name...
I tried to play around with eval, but didn't get what I wanted. Here is my code:
plot(1:10, rep(10,10), ylim=c(0,12))
rv <- 0.43
#left annotation:
mtext(paste(expression(italic(r[M])), " = ", rv), side = 1, line = -1.5, adj = 0.1)
#right annotation:
mtext(expression(paste(italic(r[M]), " = ", rv)), side = 1, line = -1.5, adj = 0.9)
This is the result:
How do i get both, nice format and value of the variable? Thanks.
btw: I know that I can get it, if I use two times mtext and play around with adj and stuff. But I would really like to get it in one call or without playing around with the position of two annotations.
The bquote function will create an expression and alow substitution of values using .(var) syntax. for your case do something like:
text( 5,1, bquote( italic(r[M]) == .(rv) ) )
Just combine what you have and plot two pieces, joined by using adj:
R> plot(1:10, rep(10,10), ylim=c(0,12))
R> text(2,12, expression(paste(italic(r[M]))), adj=1)
R> text(2,12, paste("=", rv), adj=0)

Resources