Histogram in R - x-axis not centered properly - r

I have a histogram from a list d of values that I make by simply typing
hist(d)
And this is what I get:
How can I make it such that the x-axis extends all the way left to the origin of this plot (the bottom left corner)? Why does it cut off at -0.4?

Macro's answer is by far the simplest route. However, if you really are unhappy with with the default behavior of hist (really, it's the default behavior of axis I suppose) you can always suppress the axes and draw them yourself:
set.seed(123)
d <- rnorm(1000)
hist(d,axes = FALSE)
axis(1,at = seq(-3,3,1),labels = TRUE,pos = 0)
axis(2,pos = -3)
As for the "why?", the defaults for drawing axes have to be set at something, and so there's a lot of code under there that tries pretty hard to ensure that the axis and tick labels are "pretty" according to the sensibilities of, well, whoever wrote it. In general, I think it does a good job, but of course not everyone agrees.

you can tweak the range of x using the xlim tag. For example, try
hist(d,xlim=c(-10,10))

Two suggestions:
#See if this is sufficient:
hist(...)
box()
#If not, try custom axes:
hist(..., xlim = c(-.5, .5), axes = F)
box()
axis(1, seq(-.5, .5, length = 6))
axis(2, seq(0, 30, by = 5))

Related

How to get a "perfect " Y-axis for hist(nclass=nclass.scott)?

Occasionally hist(..., nclass=nclass.scott) produces a histogram where the maximum bar extends over the top of the y axis. You may try this example a few times:
x <- sample(1000000, 500, replace=TRUE)
h <- hist(x,nclass=nclass.scott)
text(x=h$mids, y=h$counts, labels=h$counts, pos=3, col="red")
Example:
Occasionally the red number over the highest bar cannot be presented as it seems to be clipped by the plot region. I could add ylim=..., but it's quite tricky to get the maximum height of the bar.
Even when knowing the maximum height, ylim=(0, max) has the problem that max may be ignored: For example, when maximum is 527, then the upper displayed y-axis label is 500, even if ylim=(0, 527) is specified. When using 600 instead, it works, but then the y-axis is a bit too long...
If that is not a bug of R (3.3.3), what is an elegant (minimalistic) solution?
I think you need to set par(xpd= T) in your graph to avoid the trimming.
?par
xpd
A logical value or NA. If FALSE, all plotting is clipped to the
plot region, if TRUE, all plotting is clipped to the figure region,
and if NA, all plotting is clipped to the device region. See also
clip.
You can do it better by collaborating with usr option and xpd.Upon observation the bars seems going out of chart but it is not the bars that are going outside the chart but the axis being restricted to the labels. Hence to fix the labels we can choose to use usr. In case someone wants to play with the margin, one can also use mar.
library(RColorBrewer)
par(mfrow=c(1,1),xpd=T,yaxs="i")
x <- sample(1000000, 500, replace=TRUE)
h <- hist(x,nclass=nclass.scott,axes=FALSE,col=brewer.pal(10,"Set3"))
# usr <- par("usr")
at <- c(0, 10,30, par("usr")[4])
axis(2,at=at,labels = round(at))
text(x=h$mids, y=h$counts, labels=h$counts, pos=3, col="red")
usr
A vector of the form c(x1, x2, y1, y2) giving the extremes of the
user coordinates of the plotting region. When a logarithmic scale is
in use (i.e., par("xlog") is true, see below), then the x-limits will
be 10 ^ par("usr")[1:2]. Similarly for the y-axis.
You may want to run it several times, I have run it for many times, the bar won't seems to go outside the chart now.
Output:
What you describe is not a bug. You are using functionality to draw a histogram and then you want to add text to it. The function has not been designed for that, hence you need to reserve some additional white space for the text.
I suggest you run the function once, to get the "base values" of the graph. Then run the function again with adjusted scale (extra space for the text). In order to achieve this, you could use the following code
set.seed(9876) ### for reproducibility
x <- sample(1000000, 500, replace = TRUE)
h <- hist(x, nclass = nclass.scott, plot = FALSE)
### use the info from the previous call to adjust the y-scale with a constant
hist(x, nclass = nclass.scott, ylim = c(0, max(h$counts) + 10))
text(x = h$mids, y = h$counts, labels = h$counts, pos = 3, col = "red")
### ... or add a proportion (a little bit more robust)
hist(x, nclass = nclass.scott, ylim = c(0, max(h$counts) * 1.075))
text(x = h$mids, y = h$counts, labels = h$counts, pos = 3, col = "red")
Please let me know whether this is what you want.

Draw abline outside of plot margins on one side only

I'm working on an R plot that will be separated into two parts by a vertical line I'm creating with abline().I would like that abline to go over the boundaries of my plot on one side only.
I found this helpful post about setting par(xpd=). However, I could not figure out how to get this command make the line go over the plot border on one side only, as outlined in the screenshot below.
Is there a way to do this in base R? (Or do I have to rebuild the
whole thing in ggplot etc?)
I feel that the key might the differences between figure region,
device region, etc. but was unable to really determine the difference
between those. I looked at this
source
but at least for my plot those settings seem to amount to the same
thing - it would be cool if anyone had some help here as well!
Here's my approach:
plot(100, 100)
par(xpd=TRUE)
abline(v=70, lty=3)
And what I get / want:
Any help is appreciated!
Use lines. Set limits of y as you want.
plot(100, 100)
par(xpd = TRUE)
lines(x = c(70,70), y = c(45, par('usr')[4]), lty = 2)
# par('usr') gives the 4 extremes of plot
# par('usr')[4] gives the extreme on top
Another option is to not mess with xpd and use axis instead. Use tck to define the length of line beyond the plot. tck = -0.25 means the length is one fourth of the plot height towards bottom.
plot(100, 100)
par(xpd = FALSE) #Only because we made TRUE above
abline(v = 70, lty = 2)
axis(1, at = 70, labels = NA, tck = -0.25, lty = 2)

R histogram missing negative x labels

I am trying to generate a histogram in R, but some of the x labels are missing.
Here is the code I wrote:
> tmp <- hist(x, breaks=-3.5:(max(x)+1), xaxt="n", right=FALSE, xlab="log(MRS)",main="Pairwise Family-Health")
> axis(1, at=tmp$mids, labels=-3.5:max(x))
(The x values should be -3.5,-2.5,-1.5,-0.5, 0.5, 1.5, 2.5, 3.5, and the bars centering at these values.)
Does anyone know what the problem might be? Thanks!
In addition to the methods suggested in the comments (making the plot bigger, or making the text smaller), you may also want to look at the staxlab function in the plotrix package which automates a stacked label approach (puts the labels alternating on 2 or more lines to include more labels but still prevent overlap).
Try using the gap.axis argument within the axis function. So something like,
axis(side = 1, at = seq(-500000, 500000, by = 100000), gap.axis = 0.25)`
helped me when I had the same problem.

Set the number of divisions on plotting axes [duplicate]

I am creating a plot in R and I dont like the x axis values being plotted by R.
For example:
x <- seq(10,200,10)
y <- runif(x)
plot(x,y)
This plots a graph with the following values on the X axis:
50, 100, 150, 200
However, I want to plot the 20 values 10,20, 30 ... 200 stored in variable x, as the X axis values. I have scoured through countless blogs and the terse manual - after hours of searching, the closest I've come to finding anything useful is the following (summarized) instructions:
call plot() or par(), specifying argument xaxt='n'
call axis() e.g. axis(side = 1, at = seq(0, 10, by = 0.1), labels = FALSE, tcl = -0.2)
I tried it and the resulting plot had no x axis values at all. Is it possible that someone out there knows how to do this? I can't believe that no one has ever tried to do this before.
You'll find the answer to your question in the help page for ?axis.
Here is one of the help page examples, modified with your data:
Option 1: use xaxp to define the axis labels
plot(x,y, xaxt="n")
axis(1, xaxp=c(10, 200, 19), las=2)
Option 2: Use at and seq() to define the labels:
plot(x,y, xaxt="n")
axis(1, at = seq(10, 200, by = 10), las=2)
Both these options yield the same graphic:
PS. Since you have a large number of labels, you'll have to use additional arguments to get the text to fit in the plot. I use las to rotate the labels.
Take a closer look at the ?axis documentation. If you look at the description of the labels argument, you'll see that it is:
"a logical value specifying whether (numerical) annotations are
to be made at the tickmarks,"
So, just change it to true, and you'll get your tick labels.
x <- seq(10,200,10)
y <- runif(x)
plot(x,y,xaxt='n')
axis(side = 1, at = x,labels = T)
# Since TRUE is the default for labels, you can just use axis(side=1,at=x)
Be careful that if you don't stretch your window width, then R might not be able to write all your labels in. Play with the window width and you'll see what I mean.
It's too bad that you had such trouble finding documentation! What were your search terms? Try typing r axis into Google, and the first link you will get is that Quick R page that I mentioned earlier. Scroll down to "Axes", and you'll get a very nice little guide on how to do it. You should probably check there first for any plotting questions, it will be faster than waiting for a SO reply.
Hope this coding will helps you :)
plot(x,y,xaxt = 'n')
axis(side=1,at=c(1,20,30,50),labels=c("1975","1980","1985","1990"))
In case of plotting time series, the command ts.plot requires a different argument than xaxt="n"
require(graphics)
ts.plot(ldeaths, mdeaths, xlab="year", ylab="deaths", lty=c(1:2), gpars=list(xaxt="n"))
axis(1, at = seq(1974, 1980, by = 2))

How to specify the actual x axis values to plot as x axis ticks in R

I am creating a plot in R and I dont like the x axis values being plotted by R.
For example:
x <- seq(10,200,10)
y <- runif(x)
plot(x,y)
This plots a graph with the following values on the X axis:
50, 100, 150, 200
However, I want to plot the 20 values 10,20, 30 ... 200 stored in variable x, as the X axis values. I have scoured through countless blogs and the terse manual - after hours of searching, the closest I've come to finding anything useful is the following (summarized) instructions:
call plot() or par(), specifying argument xaxt='n'
call axis() e.g. axis(side = 1, at = seq(0, 10, by = 0.1), labels = FALSE, tcl = -0.2)
I tried it and the resulting plot had no x axis values at all. Is it possible that someone out there knows how to do this? I can't believe that no one has ever tried to do this before.
You'll find the answer to your question in the help page for ?axis.
Here is one of the help page examples, modified with your data:
Option 1: use xaxp to define the axis labels
plot(x,y, xaxt="n")
axis(1, xaxp=c(10, 200, 19), las=2)
Option 2: Use at and seq() to define the labels:
plot(x,y, xaxt="n")
axis(1, at = seq(10, 200, by = 10), las=2)
Both these options yield the same graphic:
PS. Since you have a large number of labels, you'll have to use additional arguments to get the text to fit in the plot. I use las to rotate the labels.
Take a closer look at the ?axis documentation. If you look at the description of the labels argument, you'll see that it is:
"a logical value specifying whether (numerical) annotations are
to be made at the tickmarks,"
So, just change it to true, and you'll get your tick labels.
x <- seq(10,200,10)
y <- runif(x)
plot(x,y,xaxt='n')
axis(side = 1, at = x,labels = T)
# Since TRUE is the default for labels, you can just use axis(side=1,at=x)
Be careful that if you don't stretch your window width, then R might not be able to write all your labels in. Play with the window width and you'll see what I mean.
It's too bad that you had such trouble finding documentation! What were your search terms? Try typing r axis into Google, and the first link you will get is that Quick R page that I mentioned earlier. Scroll down to "Axes", and you'll get a very nice little guide on how to do it. You should probably check there first for any plotting questions, it will be faster than waiting for a SO reply.
Hope this coding will helps you :)
plot(x,y,xaxt = 'n')
axis(side=1,at=c(1,20,30,50),labels=c("1975","1980","1985","1990"))
In case of plotting time series, the command ts.plot requires a different argument than xaxt="n"
require(graphics)
ts.plot(ldeaths, mdeaths, xlab="year", ylab="deaths", lty=c(1:2), gpars=list(xaxt="n"))
axis(1, at = seq(1974, 1980, by = 2))

Resources