plottext on horizontal bar in R - r

I am trying to plot the barchart and want to show the percentage on horizontal line end.. Not able to get ..whats the mistake
y <- c('Others(27%)','Environment','Family Life & children','Combating terrorism','Pensions',
'Europe', 'Housing', 'Education', 'Tax','Benefits','Immigration & Assylum','Health','Economy')
x <- c(27,10,12,15,18,20,20,21,21,25,42,46,49)
mylabels <- c('....27%','10%','12%','15%','18%','20%','20%','21%','21%','25%','42%','46%','49%')
par(mar=c(5,10,4,2)+0.1)
usr <- par( "usr" )
my_bar<-barplot(x,main="British Voters Election Priority (2015)", horiz=TRUE,las = 1,
names.arg=y, xlim=c(0, 60), border = 'black',
col=rev(topo.colors(14)),
xlab="Percentage (%)")
abline(v=x, col='grey', type="l", lty=2)
#text(myvect1, b[1,], mylabels, col="white", adj=1)
text(my_bar, mylabels, cex=1)

If you want the numbers to be displayed at the end of the bars, just extract the numeric characters out of "mylabels" to get the appropiate x-coordinates and set pos = 4 to display them on the right of the bars. As for the colours for the bars, just pick some palette that suits your wishes or specify all 13 colors manually. There are tons of cheatsheets throughout the web with different color patterns for R.
my_bar<-barplot(x,main="British Voters Election Priority (2015)", horiz=TRUE,las = 1,
names.arg=y, xlim=c(0, 60), border = 'black',
col = palette(rainbow(13)),
xlab="Percentage (%)")
abline(v=x, col='grey', type="l", lty=2)
#text(myvect1, b[1,], mylabels, col="white", adj=1)
text(as.numeric(gsub("\\D", "", mylabels)), my_bar, mylabels, cex=1, pos = 4)

You did not specify x-coordinates for where the tekst should be plotted. Your code now took the values of my_bar for both the x-coordinates and the y-coordinates. If I am correct you want something like this.
Just use this line of code at the end in order to get that:
text(60, my_bar, mylabels, cex=1, pos = 2)

Related

How do I find the correct coordinates to align labels with barplot bars?

I'm creating a graphic that has a few different graph elements, using layout() to define plotting regions. I have a separate region for labels that need to align to bars on a barplot in an adjacent plotting region.
I can take a guess at where to plot the labels so that they line up - but the number of these locations will vary so this is not an ideal solution.
Here's an example of what I'm trying to do:
labs <- paste("Some text", letters[1:9])
datA <- table(sample(letters[1:9], size=200, replace=TRUE, prob=rep(c(0.1,0.2,0.3),3)))
layout(matrix(c(1,2,3,3), 2, 2, byrow=TRUE), widths=c(1,2), heights=c(6,1))
plot.new()
text(x=1, y=seq(0.05,1.0,0.111), labels=labs, adj=1, cex=1.4)
barplot(datA, horiz=TRUE, las=1, axes=F, yaxt="n")
How can I find the correct values to plot the labels?
(I'm aware that it looks like this can be solved by just plotting the labels with the barplot - this is not a viable solution for what I'm doing).
The output of barplot gives the heights so:
bp <- barplot(datA, horiz=TRUE, las=1, axes=F, yaxt="n")
text(0*bp, bp, labs, col = "blue", pos = 4)

Plot average of values in single plot

I want to plot single bar in a graph so it would look like picture below
I created test data and calculate its mean.
value <- c(99,44,100,120,88)
value_mean <- mean(value)
And plot them using below code
barplot(value_mean, horiz=T, width=30, cex.names=0.5 ,ylim=c(0,200), col="red")
Buth the output is not even close.
I've also looked at this links
Single bar barchart in ggplot2, R
R Barplot with one bar - how to plot correctly
So my output should be something like the first picture. I was thinking that could solve ggplot.
If everything else fails, you can draw a rectangle like this:
par(mar = c(12, 2, 12, 2))
plot(0, type="n", ylim=c(-1, 1), xlim=c(0, 200), axes = F, bty = "n",ylab="", xlab="label")
rect(0, -.7, value_mean, .7, col="red", border=NA)
text(value_mean, 0, pos=4, label=value_mean)
axis(1, at=seq(0, 200, by=40))

Adding label to secondary axis in R

I have this code:
# Plotting everything
plot( p1, col= "lightgreen", xlim=c(-2.5,4.5), ylim=c(0, 700), main="Daily Total Precipitation for AR and Oct-May", xlab="ln(x)" , ylab="Frequency", xaxt = "n") # first histogram
plot( p2, col="red", xlim=c(-2.5,4.5), ylim=c(0, 700), xaxt = "n" , add=T)
# Adding in text labels on top of the bars
text(x, y, paste(round(percents,2),"%"), cex=0.50, pos=3, offset=0.3, col="black")
axis(side=1, at=breaks) # new x-axis
# parameter that needs to be set to add a new graph on top of the other ones
par(new=T)
plot(x, percents, xlim=c(-2.5,4.5), type="l", col="yellow", lwd=3.0, axes=F, ylab=NA, xlab=NA)
axis(side=4, at=seq(0,100,by=10), col="yellow", col.axis="yellow") # additional y-axis
mtext("Percent", side=4, col="yellow")
# legend settings
legend("topleft", c("AR", "Oct-May"), lwd=10, col=c("red", "lightgreen"))
Which produces this graph:
And I can't seem to figure out how to get the secondary y-axis label to show up in the correct position. Any help or suggestions is greatly appreciated.
Edit: Using RStudio.
One option is to specify the line argument to mtext(). In the example below I add a couple more lines to the right (side = 4) margin of the plot using par(), and then I draw three labels using mtext() at the default (line = 0), line 3 (line = 3), and line -3 (line = -3):
op <- par(mar = c(5,4,4,4) + 0.1)
plot(1:10)
mtext("line0", side = 4)
mtext("line3", side = 4, line = 3)
mtext("line-3", side = 4, line = -3)
par(op)
Note that line numbers increase away from the plot region and that negative line values move into the plot region, or to the left of the right boundary of the plot region.
It takes a little playing with the number of margin lines (as set in par(mar = x)) and which line you want to draw on using mtext(), but a little trial and error should get you what you want.
Note also that you don't need to specify integer values for the line argument. You can specify fractions of lines too: line = 2.5.

Change the number of tick marks on a figure in R

I created a figure of two plots (two years) of climate data (temp and precip) that looks exactly like I want it, except that one of my axes has too many tick marks. With everything I have going on with this figure, I can't find a way to specify fewer tick marks without messing up other parts. I would also like to specify where the tick marks are. Here is the figure:
You can see that the tick marks for the top axis just blur together and the numbers chosen are not very meaningful to me. How can I tell R what I really want?
Here are the datasets I am using: cobs10 and
cobs11.
And here is my code:
par(mfrow=c(2,1))
par(mar = c(5,4,4,4) + 0.3)
plot(cobs10$day, cobs10$temp, type="l", col="red", yaxt="n", xlab="", ylab="",
ylim=c(-25, 30))
axis(side=3, col="black", at=cobs10$day, labels=cobs10$gdd)
at = axTicks(3)
mtext("Thermal Units", side=3, las=0, line = 3)
axis(side=2, col='red', labels=FALSE)
at= axTicks(2)
mtext(side=2, text= at, at = at, col = "red", line = 1, las=0)
mtext("Temperature (C)", side=2, las=0, line=3)
par(new=TRUE)
plot(cobs10$gdd, cobs10$precip, type="h", col="blue", yaxt="n", xaxt="n", ylab="",
xlab="")
axis(side=4, col='blue', labels=FALSE)
at = axTicks(4)
mtext(side = 4, text = at, at = at, col = "blue", line = 1,las=0)
mtext("Precipitation (cm)", side=4, las=0, line = 3)
par(mar = c(5,4,4,4) + 0.3)
plot(cobs11$day, cobs11$temp, type="l", col="red", yaxt="n", xlab="Day of Year",
ylab="", ylim=c(-25, 30))
axis(side=3, col="black", at=cobs11$day, labels=cobs11$gdd)
at = axTicks(3)
mtext("", side=3, las=0, line = 3)
axis(side=2, col='red', labels=FALSE)
at= axTicks(2)
mtext(side=2, text= at, at = at, col = "red", line = 1, las=0)
mtext("Temperature (C)", side=2, las=0, line=3)
par(new=TRUE)
plot(cobs11$gdd, cobs11$precip, type="h", col="blue", yaxt="n", xaxt="n", ylab="",
xlab="", ylim=c(0,12))
axis(side=4, col='blue', labels=FALSE)
at = axTicks(4)
mtext(side = 4, text = at, at = at, col = "blue", line = 1,las=0)
mtext("Precipitation (cm)", side=4, las=0, line = 3)
Thanks for thinking about it.
You've pretty much got the solution already:
axis(side=3, col="black", at=cobs10$day, labels=cobs10$gdd)
Except, you are asking to have ticks and labels at every single entry.
Take a look at the function pretty:
at <- pretty(cobs10$day)
at
# [1] 0 100 200 300 400
These are where the ticks should be placed on the x-axis. Now you need to find the corresponding labels. This is not straigtforward, but we will get:
lbl <- which(cobs10$day %in% at)
lbl
# [1] 100 200 300
lbl <- c(0, cobs10$gdd[lbl]
axis(side=3, at=at[-5], labels=lbl)
Update
I've been a bit annoyed by your use of three different series in a single plot. There are many reasons this is troublesome.
Having two y-values are always troublesome see this article from Stephen Few (go to page 5 for my favorite example); in your case it is not that serious due to the nature of the plots and your use of colours to indicate which y-axis the values belong to. But still, on principle.
Axis ticks should have a fixed function, e.g. linear or logarithm. With your Thermal Units, they appear "randomly" (I know that is not the case, but for an outsider they do).
We gotta do something about your x-axis ticks that just refer to "day of year".
First up, we take a look at your data and see what can be done naively. We recognize that your ''date'' variable is actual dates. Let's exploit it and make R aware of it!
cobs10 <- read.table('cobs10.txt',as.is=TRUE)
cobs10$date <- as.Date(cobs10$date)
plot(temp ~ date, data=cobs10, type='l')
Here, I really like the x-axis ticks and had some trouble replicating it. ''pretty'' on dates insisted on either 4 ticks or 12 ticks. But we will come back to that later.
Next, we can do something about the overlay plotting. Here I use ''par(mfrow=c(3,1))'' to instruct R to have three multiple plots stacked in a single window; with these multiple plots we can differentiate between inner and outer margins. The ''mar'' and ''oma'' arguments refers to the inner and outer margin.
Lets put all three variable together!
par(mfrow=c(3,1), mar=c(0.6, 5.1, 0, 0.6), oma=c(5.1, 0, 1, 0))
plot(temp ~ date, data=cobs10, type='l', ylab='Temperatur (C)')
plot(precip ~ date, data=cobs10, type='l', ylab='Precipitation (cm)')
plot(gdd ~ date, data=cobs10, type='l', ylab='Thermal units')
This looks okay, but not with ticks on top of the plots. Not good. Naturally, we can enable ticks in the first two plots (with ''plot(..., xaxt='n')''), but this will distort the bottom plot. So you will need to do so for all three plots and then add the axis to the outer plotting region.
par(mfrow=c(3,1), mar=c(0.6, 5.1, 0, 0.6), oma=c(5.1, 0, 1, 0))
plot(temp ~ date, data=cobs10, type='l', xaxt='n', ylab='Temperatur (C)')
plot(precip ~ date, data=cobs10, type='l', xaxt='n', ylab='Precipitation (cm)')
plot(gdd ~ date, data=cobs10, type='l', xaxt='n', ylab='Thermal units')
ticks <- seq(from=min(cobs10$date), by='2 months', length=7)
lbl <- strftime(ticks, '%b')
axis(side=1, outer=TRUE, at=ticks, labels=lbl)
mtext('2010', side=1, outer=TRUE, line=3, cex=0.67)
Since ''pretty'' doesn't behave as we want it to, we use ''seq'' to make the sequence of x-axis ticks. Then we format the dates to just display an abbreviation of the month name, but this is done with regard to local settings (I live in Denmark), see ''locale''.
To add the axis-ticks and a label to the outer region, we must remember to specify ''outer=TRUE''; otherwise it is added to the last subplot.
Also note that I specified ''cex=0.67'' to match the font size of the x-axis to the y-axis.
Now I agree that displaying the thermal units in a individual subplot is not optimal, although it is the correct way of displaying it. But there was the issue with the ticks. What we really want is to display some nice values that clearly display that they are not linear. But your data does not necessarily contain these nice values, so we will have to interpolate them ourselves.
For this, I use the ''splinefun''
lbl <- c(0, 2, 200, 1000, 2000, 3000, 4000)
thermals <- splinefun(cobs10$gdd, cobs10$date) # thermals is a function that returns the date (as an integer) for a requested value
thermals(lbl)
## [1] 14649.00 14686.79 14709.55 14761.28 14806.04 14847.68 14908.45
ticks <- as.Date(thermals(lbl), origin='1970-01-01') # remember to specify an origin when converting an integer to a Date.
Now the thermal ticks are in place, lets try it.
par(mfrow=c(2,1), mar=c(0.6, 5.1, 0, 0.6), oma=c(5.1, 0, 4, 0))
plot(temp ~ date, data=cobs10, type='l', xaxt='n', ylab='Temperatur (C)')
plot(precip ~ date, data=cobs10, type='l', xaxt='n', ylab='Precipitation (cm)')
usr <- par('usr')
x.pos <- (usr[2]+usr[1])/2
ticks <- seq(from=min(cobs10$date), by='2 months', length=7)
lbl <- strftime(ticks, '%b')
axis(side=1, outer=TRUE, at=ticks, labels=lbl)
mtext('2010', side=1, at=x.pos, line=3)
lbl <- c(0, 2, 200, 1000, 2000, 3000, 4000)
thermals <- splinefun(cobs10$gdd, cobs10$date) # thermals is a function that returns the date (as an integer) for a requested value
ticks <- as.Date(thermals(lbl), origin='1970-01-01') # remember to specify an origin when converting an integer to a Date.
axis(side=3, outer=TRUE, at=ticks, labels=lbl)
mtext('Thermal units', side=3, line=15, at=x.pos)
Update I changed the mtext function calls in the last code block to ensure that the x-axis texts are centred on the plotting region, not the entire region. You might want to tweak the vertical position by changing the line-argument.

Plotting a grid behind data, not in front in R

I like to produce my own grid lines when plotting so I can control tick marks, etc. and I am struggling with this with the 'hist' plotting routine.
hist(WindSpeed, breaks=c(0:31), freq=TRUE, col="blue", xaxt="n", yaxt="n", xlab="Wind Speed (m/s)",main="Foo", cex.main=1.5, cex.axis=1, cex.lab=1, tck=1, font.lab=2)
axis(1, tck=1, ,col.ticks="light gray")
axis(1, tck=-0.015, col.ticks="black")
axis(2, tck=1, col.ticks="light gray", lwd.ticks="1")
axis(2, tck=-0.015)
minor.tick(nx=5, ny=2, tick.ratio=0.5)
box()
Plot:
I have then just been able to use the 'lines' or 'points' command to replot the data over top for other types of plots, but with the histogram its not so easy.
Any help would be great.
I added my code below and image based upon John's response...
I added my code below and image based upon John's response...
hist(WindSpeed, breaks=30, freq=TRUE, col="blue", xaxt="n", yaxt="n", xlab="Wind Speed (m/s)",main="Foo", cex.main=1.5, cex.axis=1, cex.lab=1, font.lab=2)
axis(1, tck=1, col.ticks="light gray")
axis(1, tck=-0.015, col.ticks="black")
axis(2, tck=1, col.ticks="light gray", lwd.ticks="1")
axis(2, tck=-0.015)
minor.tick(nx=5, ny=2, tick.ratio=0.5)
box()
hist(WindSpeed, add=TRUE, breaks=30, freq=TRUE, col="blue", xaxt="n", yaxt="n", xlab="Wind Speed (m/s)", main="Foo", cex.main=1.5, cex.axis=1, cex.lab=1, font.lab=2)
Actually, R has a way to do this! It's the panel.first argument to plot.default, which hist calls to do most of the work. It takes an expression which is evaluated "after the plot axes are set up but before any plotting takes place. This can be useful for drawing background grids or scatterplot smooths," to quote from ?plot.default.
hist(WindSpeed, breaks=c(0:31), freq=TRUE, col="blue", xaxt="n", yaxt="n",
xlab="Wind Speed (m/s)", main="Foo",
cex.main=1.5, cex.axis=1, cex.lab=1, tck=1, font.lab=2,
panel.first={
axis(1, tck=1, col.ticks="light gray")
axis(1, tck=-0.015, col.ticks="black")
axis(2, tck=1, col.ticks="light gray", lwd.ticks="1")
axis(2, tck=-0.015)
minor.tick(nx=5, ny=2, tick.ratio=0.5)
box()
})
See How do I draw gridlines using abline() that are behind the data? for another question that uses this method.
This is relatively easy.
Generate the histogram but don't plot it.
h <- hist(y, plot = FALSE)
Now generate your base plot... I've added some features to make it look more like a standard historgram
plot(h$mids, h$counts, ylim = c(0, max(h$counts)), xlim = range(h$mids)*1.1,
type = 'n', bty = 'n', xlab = 'y', ylab = 'Counts', main = 'Histogram of y')
add your grid
grid()
add your histogram
hist(y, add = TRUE)
Or, as I discovered through this process... you can do it even easier
hist(y)
grid()
hist(y, add = TRUE, col = 'white')
This last method is just redrawing the histogram over the grid.
In R, order matters when you plot. As you've discovered, adding things to a plot adds on top of what you've plotted before. So we need a way to plot the grid first and then the histogram. Try something like this:
plot(1:10,1:10,type = "n")
grid(10,10)
hist(rnorm(100,5,1),add = TRUE)
I haven't recreated your example, since it isn't reproducible, but this general idea should work. But the key idea is to create an empty plot with the correct dimensions using the type = "n" option to plot, then add the grid, then add the histogram using the add = TRUE argument.
Note that the add argument is actually for plot.histogram, hist passes it along via ....
The base graphics solution suggested by #joran is fine. Alternatives:
d <- data.frame(x=rnorm(1000))
library(lattice)
histogram(~x,data=d,panel=function(...) {
panel.grid(...)
panel.histogram(...) }
)
Or:
library(ggplot2)
qplot(x,data=d,geom="histogram",binwidth=0.1)+theme_bw()+
labs(x="Wind speed", y="Frequency")
(But of course you will have to learn all the details of adjusting labels, titles, etc. ... I'm not actually sure how to do titles in ggplot ...)
Another methods for grid lines in background:
A)
hist( y, panel.first=grid() ) # see: help( plot.default )
box()
B)
plot.new() # new empty plot
nv <- length( pretty(x) ) - 1 # number of vertical grid lines (or set by hand)
nh <- length( pretty(y) ) - 1 # number of horizontal grid lines (or set by hand)
grid( nx = nv, ny = nh ) # preplot grid lines
par( new = TRUE ) # add next plot
plot( x, y ) # plot or hist, etc
box() # if plot hist
Arbitrary lines in background with abline:
C)
How do I draw gridlines using abline() that are behind the data?
D)
# first, be sure there is no +/-Inf, NA, NaN in x and y
# then, make the container plot with two invisible points:
plot( x = range( pretty( x ) ), y = range( pretty( y ) ), type = "n", ann = FALSE )
abline( h = hlines, v = vlines ) # draw lines. hlines, vlines: vectors of coordinates
par( new = TRUE ) # add next plot. It is not necessary with points, lines, segments, ...
plot( x, y ) # plot, hist, etc
box() # if plot hist

Resources