Why is one number missing with barplot? [duplicate] - r

When I manually add the following labels with (axis(1, at=1:27, labels=labs[0:27])):
> labs[0:27]
[1] "0\n9.3%" "1\n7.6%" "2\n5.6%" "3\n5.1%" "4\n5.7%" "5\n6.5%" "6\n7.3%" "7\n7.6%" "8\n7.5%" "9\n7%" "10\n6.2%" "11\n5.2%"
[13] "12\n4.2%" ........
I get the following:
How do I force all labels to be drawn so 1,3,5,6, and 11 are not skipped? (also, for extra credit, how do I shift the whole thing down a few pixels?)

If you want to force all labels to display, even when they are very close or overlapping, you can "trick" R into displaying them by adding odd and even axis labels with separate calls to the axis function, as follows:
labs <-c("0\n9.3%","1\n7.6%","2\n5.6%","3\n5.1%","4\n5.7%","5\n6.5%","6\n7.3%",
"7\n7.6%","8\n7.5%","9\n7%", "10\n6.2%","11\n5.2%","12\n4.2%",13:27)
n=length(labs)
plot(1:28, xaxt = "n")
axis(side=1, at=seq(1,n,2), labels=labs[seq(1,n,2)], cex.axis=0.6)
axis(side=1, at=seq(2,n,2), labels=labs[seq(2,n,2)], cex.axis=0.6)
You can play with cex.axis to get the text size that you want. Note, also, that you may have to adjust the number of values in at= and/or labels= so that they are equal.
I agree with #PLapointe and #joran that it's generally better not to tamper with R's default behavior regarding overlap. However, I've had a few cases where axis labels looked fine even when they weren't quite a full "m-width" apart, and I hit on the trick of alternating odd and even labels as a way to get the behavior I wanted.

?axis tells you that:
The code tries hard not to draw overlapping tick labels, and so will omit labels where they would abut or overlap previously drawn labels. This can result in, for example, every other tick being labelled. (The ticks are drawn left to right or bottom to top, and space at least the size of an ‘m’ is left between labels.)
Play with cex.axis so that labels are small enough to fit without overlapping
labs <-c("0\n9.3%","1\n7.6%","2\n5.6%","3\n5.1%","4\n5.7%","5\n6.5%","6\n7.3%",
"7\n7.6%","8\n7.5%","9\n7%", "10\n6.2%","11\n5.2%","12\n4.2%",12:27)
plot(1:27,xaxt = "n")
axis(side=1, at=1:27, labels=labs[0:27],cex.axis=0.35)
If you widen you graph (manually by dragging or programmatically), you can increase the size of your labels.

Although there are some good answers here, the OP didn't want to resize the labels or change anything about the plot besides fitting all of the axis labels. It's annoying, since often there appears to be plenty of room to fit all of the axis labels.
Here's another solution. Draw the plot without the axis, then add ticks with empty labels. Store the positions of the ticks in an object, so then you can go through each one and place it in the correct position on the axis.
plot(1:10, 1:10, yaxt = "n")
axis_ticks = axis(2, axTicks(2), labels = rep("", length(axTicks(2))))
for(i in axis_ticks) axis(2, i)

#PLapointe just posted what I was going to say, but omitted the bonus answer.
Set padj = 0.5 in axis to move the labels down slightly.

Perhaps draw and label one tick at a time, by calling axis repeatedly using mapply...
For example, consider the following data:
x = runif(100)*20
y = 10^(runif(100)*3)
The formula for y might look a bit odd; it gives random numbers distributed across three orders of magnitude such that the data will be evenly distributed on a plot where the y axis is on a log scale. This will help demonstrate the utility of axTicks() by calculating nice tick locations for us on a logged axis.
By default:
plot(x, y, log = "y")
returns:
Notice that 100 and 1000 labels are missing.
We can instead use:
plot(x, y, log = "y", yaxt = "n")
mapply(axis, side = 2, at = axTicks(2), labels = axTicks(2))
which calls axis() once for each tick location returned by axTicks(), thus plotting one tick at a time. The result:
What I like about this solution is that is uses only one line of code for drawing the axis, it prints exactly the default axis R would have made, except all ticks are labeled, and the labels don't go anywhere when the plot is resized:
I can't say the axis is useful in the resized example, but it makes the point about axis labels being permanent!
For the first (default) plot, note that R will recalculate tick locations when resizing.
For the second (always labeled) plot, the number and location of tick marks are not recalculated when the image is resized. The axis ticks calculated by axTicks depend upon the size of the display window when the plot is first drawn.
If you want want to force specific tick locations, try something like:
plot(x, y, log = "y", yaxt = "n")
mapply(axis, side = 2, at = c(1,10,100, 1000), labels = c("one", "ten", "hundred", "thousand"))
which yields:

axis() includes a gap.axis parameter that controls when labels are omitted. Setting this to a very negative number will force all labels to display, even if they overlap.
The padj parameter of axis() controls the y offset whilst plotting an individual axis.
par(mgp = c(3, 2, 0) will adjust the position of all axis labels for the duration of a plotting session: the second value (here 2, default 1) controls the position of the labels.
# Set axis text position, including for Y axis
par(mgp = c(3, 2, 0))
# Plot
plot(1:12, 1:12, log = 'x', ann = FALSE, axes = FALSE)
# Some numbers not plotted:
axis(1, 1:12)
# All numbers plotted, with manual offset
axis(1, 1:12, gap.axis = -100, padj = 0.5)

I had a similar problem where I wanted to stagger the labels and get them to print without losing some. I created two sets of ticks showing second set below the other to make it look as if it staggers.
xaxis_stagger = function(positions,labels) {
odd=labels[seq(1,length(labels),2)]
odd_pos=positions[seq(1,length(positions),2)]
even=labels[seq(2,length(labels),2)]
even_pos=positions[seq(2,length(positions),2)]
axis(side=1,at=odd_pos,labels=odd)
axis(side=1,at=even_pos,labels=even,padj=1.5)
}
So you give the positions where you want the ticks to be and the labels for those ticks and this would then re-organise it into two sets of axis and plot them on the original plot. Original plot would be done with xaxt="n".

Related

Why is `ann=FALSE` not working in the boxplot call in R?

Trying to produce both a stripchart and a boxplot of the same (transformed) data but (because the boxplot is shifted down a tad) I don't want the axis labels twice:
set.seed(3121975)
bee = list(x1=rnbinom(50, mu = 4, size = .1),
x2=rnbinom(30,mu=6,size=.1),
x3=rnbinom(40,mu=2,size=.1))
f = function(x) asinh(sqrt(4*x+1.5))
stripchart(lapply(bee,f),method="stack",offset=.13,ylim=c(.8,3.9))
boxplot(lapply(bee,f),horizontal=TRUE,boxwex=.05,at=(1:3)-.1,add=TRUE,ann=FALSE)
Other things that don't work include: (i) leaving ann to take its default value of !add, (ii) specifying labels for ylab.
I presume I have missed something obvious but I am not seeing what it might be.
Just add yaxt = 'n' into boxplot() to suppress plotting of the y-axis. The argument ann controls axis titles and overall titles, not the axis itself.

How do I add custom ranges and points in the axes of a Base R plot?

Let's consider a vector and plot it.
s1 <- sample(100:1000,32,replace = T)
plot(s1)
The plot I get has a Y-Axis that ranges from 0-1000 with points in the intervals of 200 (0,200,400,600,800,1000) and this is happening implicitly.
If I use ylim argument, apparently or to be honest, evidently, I can now have a custom range,
plot(s1,ylim = c(0,1500))
The points on Y Axis now are 0-1500 as indicated but with the points in the intervals of 500 (0,500,1000,1500), this is happening without my control.
My question, how can I have custom points with custom intervals on the X or Y axis?
use axis() to set your limits : on either x, y, or both
s1 <- sample(100:1000,32,replace = T)
plot(s1, yaxt = "n") # `yaxt` prevents y-axis labels to be printed
axis(2, yaxp=c(10, 1000, 10), las=2) # 'las' helps to align the tick mark labels along the axis or perpendicular
# 'yaxp' helps to set the break points you desire. Learn more from ?par

Base Plot, correctly defining axis [duplicate]

How can I change the spacing of tick marks on the axis of a plot?
What parameters should I use with base plot or with rgl?
There are at least two ways for achieving this in base graph (my examples are for the x-axis, but work the same for the y-axis):
Use par(xaxp = c(x1, x2, n)) or plot(..., xaxp = c(x1, x2, n)) to define the position (x1 & x2) of the extreme tick marks and the number of intervals between the tick marks (n). Accordingly, n+1 is the number of tick marks drawn. (This works only if you use no logarithmic scale, for the behavior with logarithmic scales see ?par.)
You can suppress the drawing of the axis altogether and add the tick marks later with axis().
To suppress the drawing of the axis use plot(... , xaxt = "n").
Then call axis() with side, at, and labels: axis(side = 1, at = v1, labels = v2). With side referring to the side of the axis (1 = x-axis, 2 = y-axis), v1 being a vector containing the position of the ticks (e.g., c(1, 3, 5) if your axis ranges from 0 to 6 and you want three marks), and v2 a vector containing the labels for the specified tick marks (must be of same length as v1, e.g., c("group a", "group b", "group c")). See ?axis and my updated answer to a post on stats.stackexchange for an example of this method.
With base graphics, the easiest way is to stop the plotting functions from drawing axes and then draw them yourself.
plot(1:10, 1:10, axes = FALSE)
axis(side = 1, at = c(1,5,10))
axis(side = 2, at = c(1,3,7,10))
box()
I have a data set with Time as the x-axis, and Intensity as y-axis. I'd need to first delete all the default axes except the axes' labels with:
plot(Time,Intensity,axes=F)
Then I rebuild the plot's elements with:
box() # create a wrap around the points plotted
axis(labels=NA,side=1,tck=-0.015,at=c(seq(from=0,to=1000,by=100))) # labels = NA prevents the creation of the numbers and tick marks, tck is how long the tick mark is.
axis(labels=NA,side=2,tck=-0.015)
axis(lwd=0,side=1,line=-0.4,at=c(seq(from=0,to=1000,by=100))) # lwd option sets the tick mark to 0 length because tck already takes care of the mark
axis(lwd=0,line=-0.4,side=2,las=1) # las changes the direction of the number labels to horizontal instead of vertical.
So, at = c(...) specifies the collection of positions to put the tick marks. Here I'd like to put the marks at 0, 100, 200,..., 1000. seq(from =...,to =...,by =...) gives me the choice of limits and the increments.
And if you don't want R to add decimals or zeros, you can stop it from drawing the x axis or the y axis or both using ...axt. Then, you can add your own ticks and labels:
plot(x, y, xaxt="n")
plot(x, y, yaxt="n")
axis(1 or 2, at=c(1, 5, 10), labels=c("First", "Second", "Third"))
I just discovered the Hmisc package:
Contains many functions useful for data analysis, high-level graphics, utility operations, functions for computing sample size and power, importing and annotating datasets, imputing missing values, advanced table making, variable clustering, character string manipulation, conversion of R objects to LaTeX and html code, and recoding variables.
library(Hmisc)
plot(...)
minor.tick(nx=10, ny=10) # make minor tick marks (without labels) every 10th

axis length (not scaling!) in a scatter plot

How to change the axis length? for ex:
s <- data.table(school=rep(1:3,5), wave=c(rep(1,7), rep(2,8)), v1=rpois(15,10))
plot(s$wave,s$v2)
I get a scatter plot where the data is at the edges of the plot (a lot of white space in the graph). changing the xaxp values doesn't help (tried xaxp=c(-1, +2,4)) but nothing happened) and when I try to define it a factor I get a box plot. I know I can "squeeze" it when i save to .png but is there any other way?
I tried to upload pictures to convey the problem but I don't have enough reputation.
edit-thanks for whoever uploaded it (although the axis are reversed - wave is the x and V2 is the y). the thing is that there is a lot of "free space" between the 1st and the 2nd wave. the position is perfect when i define the wave a factor (it's centered and each factor is half the axis length) but it keeps giving me a box plot!
You can add a lot of values to your plot function, like colour, title, and also the limits of the axsis
Your code:
s <- data.frame(school=rep(1:3,5), wave=c(rep(1,7), rep(2,8)), v1=rpois(15,10))
plot(s$wave,s$v2)
And now just add some more:
plot(
x = s$wave,
y = s$v2,
col = "red",
main = "This is my title",
xlab = "the label of the x-axis",
ylab = "the label of the y-axis",
xlim = c(-5, 5), # the limits of the x-axis,
ylim = c(-4, 10) # the limits of the y-axis
)
You can add much more like size and type of the points ...
just as jlhoward mentioned
i found a function in the "lattice" package that does exactly what i want - a boxplot without the box.
the function is called stripplot.
http://www.math.ucla.edu/~anderson/rw1001/library/base/html/stripplot.html
thank you all for the help

Controlling axis ticks and axis lines separately on R lattice xyplot

How can I go about removing the box around an xyplot, while keeping the axis scale tick marks? In the spirit of Edward Tufte's minimalist data graphic aesthetic, these axis lines are "non-data ink," and can (should?) be "erased."
library(lattice)
my.df <- data.frame(x=-10:10)
my.df$y <- my.df$x^2
xyplot(y~x,data=my.df)
It seems that the trellis display parameters (e.g. axis.line$col) control both the axis lines and axis ticks together:
xyplot(y~x,data=my.df,
par.settings=list(axis.line=list(col="transparent")))
...which is not the desired result, so it doesn't look like there's a simple way to turn off the lines while leaving the box.
The best I've been able to come up with is a brute-force hack, where I build the tick marks by hand using panel.segments:
at.x=pretty(c(-10,10))
at.y=pretty(c(0,100))
xyplot(y~x,data=my.df,
par.settings=list(axis.line=list(col="transparent")),
scales=list(x=list(at=at.x,labels=at.x),
y=list(at=at.y,labels=at.y)),
panel=function(...){
panel.xyplot(...)
panel.segments(x0=at.x,x1=at.x,y0=-4,y1=-2)
panel.segments(x0=-11.5,x1=-11,y0=at.y,y1=at.y)
}
)
This is close to the desired result, but there's quite a bit of fiddling required to get the tick marks to be a reasonable length and offset a "nice" distance from the data points. These values won't translate from one graphic to the next. Plus, note that the axis labels are now padded too far from the tick marks. I'm sure there's a way to reduce that padding, but that would only make the code even uglier and less portable.
So how can one go about suppressing just the lines that make up the "box" around the plot area, while leaving the tick marks and axis labels intact? Bonus points if this approach could also be used to suppress some, but not all of the lines (e.g. leave the left and lower lines, but suppress the top and right lines).
This is still a bit hacky, but at least you don't have to do any figuring by hand. It uses a combination of par.settings and a custom axis function that takes an argument line.col and temporarily changes the axis line color by a call to trellis.par.set:
EDIT (removed unnecessary changing of trellis settings)
xyplot(y~x,data=my.df, par.settings = list(axis.line = list(col = "transparent")),
# Pass custom axis function to argument 'axis'
axis = function(side, line.col = "black", ...) {
# Only draw axes on the left and bottom
if(side %in% c("left","bottom")) {
# Call default axis drawing function
axis.default(side = side, line.col = "black", ...)
}
}
)
At the moment, I chalk up why line.col = "black" is required in the arguments of the custom axis function to magic. My guess is that it has to do with argument matching with the ellipses (...). Perhaps I'll be wiser tomorrow and find the true reason.
This results in:
The easiest thing to do is to use the custom axis function (axis). Just set lwd (line width) to zero and tick marks (lwd.ticks) to something else. It worked like a charm!
plot(NA,NA,type="n",xaxt="n", lwd=linewidth, xlim=c(1,24), xlab="", ylab="",ylim=c(-300,500))
axis(side = 4, tck = .05, **lwd=0, lwd.ticks=1**, line = 0, labels = NA, col= cols_border[1], col.axis = cols_black)
axis(side = 4, lwd = 0, line = -4.5, las = 1, cex.axis=axis_fontsize, col= cols_border[1], col.axis = cols_black)
mtext("Light deviations (lum/sec)",side=4, padj=-2.5, cex=title_fontsize, col="black")

Resources