Related
I am trying to get the x axis labels to be rotated 45 degrees on a barplot with no luck. This is the code I have below:
barplot(((data1[,1] - average)/average) * 100,
srt = 45,
adj = 1,
xpd = TRUE,
names.arg = data1[,2],
col = c("#3CA0D0"),
main = "Best Lift Time to Vertical Drop Ratios of North American Resorts",
ylab = "Normalized Difference",
yaxt = 'n',
cex.names = 0.65,
cex.lab = 0.65)
use optional parameter las=2 .
barplot(mytable,main="Car makes",ylab="Freqency",xlab="make",las=2)
EDITED ANSWER PER DAVID'S RESPONSE:
Here's a kind of hackish way. I'm guessing there's an easier way. But you could suppress the bar labels and the plot text of the labels by saving the bar positions from barplot and do a little tweaking up and down. Here's an example with the mtcars data set:
x <- barplot(table(mtcars$cyl), xaxt="n")
labs <- paste(names(table(mtcars$cyl)), "cylinders")
text(cex=1, x=x-.25, y=-1.25, labs, xpd=TRUE, srt=45)
Rotate the x axis labels with angle equal or smaller than 90 degrees using base graphics. Code adapted from the R FAQ:
par(mar = c(7, 4, 2, 2) + 0.2) #add room for the rotated labels
#use mtcars dataset to produce a barplot with qsec colum information
mtcars = mtcars[with(mtcars, order(-qsec)), ] #order mtcars data set by column "qsec"
end_point = 0.5 + nrow(mtcars) + nrow(mtcars) - 1 #this is the line which does the trick (together with barplot "space = 1" parameter)
barplot(mtcars$qsec, col = "grey50",
main = "",
ylab = "mtcars - qsec", ylim = c(0,5 + max(mtcars$qsec)),
xlab = "",
xaxt = "n", # Do not plot the default labels
space = 1)
#rotate 60 degrees (srt = 60)
text(seq(1.5, end_point, by = 2), par("usr")[3]-0.25,
srt = 60, adj = 1, xpd = TRUE,
labels = paste(rownames(mtcars)), cex = 0.65)
You can simply pass your data frame into the following function:
rotate_x <- function(data, column_to_plot, labels_vec, rot_angle) {
plt <- barplot(data[[column_to_plot]], col='steelblue', xaxt="n")
text(plt, par("usr")[3], labels = labels_vec, srt = rot_angle, adj = c(1.1,1.1), xpd = TRUE, cex=0.6)
}
Usage:
rotate_x(mtcars, 'mpg', row.names(mtcars), 45)
You can change the rotation angle of the labels as needed.
You may use
par(las=2) # make label text perpendicular to axis
It is written here: http://www.statmethods.net/graphs/bar.html
You can use ggplot2 to rotate the x-axis label adding an additional layer
theme(axis.text.x = element_text(angle = 90, hjust = 1))
In the documentation of Bar Plots we can read about the additional parameters (...) which can be passed to the function call:
... arguments to be passed to/from other methods. For the default method these can
include further arguments (such as axes, asp and main) and graphical
parameters (see par) which are passed to plot.window(), title() and axis.
In the documentation of graphical parameters (documentation of par) we can see:
las
numeric in {0,1,2,3}; the style of axis labels.
0:
always parallel to the axis [default],
1:
always horizontal,
2:
always perpendicular to the axis,
3:
always vertical.
Also supported by mtext. Note that string/character rotation via argument srt to par does not affect the axis labels.
That is why passing las=2 makes the labels perpendicular, although not at 45°.
Andre Silva's answer works great for me, with one caveat in the "barplot" line:
barplot(mtcars$qsec, col="grey50",
main="",
ylab="mtcars - qsec", ylim=c(0,5+max(mtcars$qsec)),
xlab = "",
xaxt = "n",
space=1)
Notice the "xaxt" argument. Without it, the labels are drawn twice, the first time without the 60 degree rotation.
I am trying to get the x axis labels to be rotated 45 degrees on a barplot with no luck. This is the code I have below:
barplot(((data1[,1] - average)/average) * 100,
srt = 45,
adj = 1,
xpd = TRUE,
names.arg = data1[,2],
col = c("#3CA0D0"),
main = "Best Lift Time to Vertical Drop Ratios of North American Resorts",
ylab = "Normalized Difference",
yaxt = 'n',
cex.names = 0.65,
cex.lab = 0.65)
use optional parameter las=2 .
barplot(mytable,main="Car makes",ylab="Freqency",xlab="make",las=2)
EDITED ANSWER PER DAVID'S RESPONSE:
Here's a kind of hackish way. I'm guessing there's an easier way. But you could suppress the bar labels and the plot text of the labels by saving the bar positions from barplot and do a little tweaking up and down. Here's an example with the mtcars data set:
x <- barplot(table(mtcars$cyl), xaxt="n")
labs <- paste(names(table(mtcars$cyl)), "cylinders")
text(cex=1, x=x-.25, y=-1.25, labs, xpd=TRUE, srt=45)
Rotate the x axis labels with angle equal or smaller than 90 degrees using base graphics. Code adapted from the R FAQ:
par(mar = c(7, 4, 2, 2) + 0.2) #add room for the rotated labels
#use mtcars dataset to produce a barplot with qsec colum information
mtcars = mtcars[with(mtcars, order(-qsec)), ] #order mtcars data set by column "qsec"
end_point = 0.5 + nrow(mtcars) + nrow(mtcars) - 1 #this is the line which does the trick (together with barplot "space = 1" parameter)
barplot(mtcars$qsec, col = "grey50",
main = "",
ylab = "mtcars - qsec", ylim = c(0,5 + max(mtcars$qsec)),
xlab = "",
xaxt = "n", # Do not plot the default labels
space = 1)
#rotate 60 degrees (srt = 60)
text(seq(1.5, end_point, by = 2), par("usr")[3]-0.25,
srt = 60, adj = 1, xpd = TRUE,
labels = paste(rownames(mtcars)), cex = 0.65)
You can simply pass your data frame into the following function:
rotate_x <- function(data, column_to_plot, labels_vec, rot_angle) {
plt <- barplot(data[[column_to_plot]], col='steelblue', xaxt="n")
text(plt, par("usr")[3], labels = labels_vec, srt = rot_angle, adj = c(1.1,1.1), xpd = TRUE, cex=0.6)
}
Usage:
rotate_x(mtcars, 'mpg', row.names(mtcars), 45)
You can change the rotation angle of the labels as needed.
You may use
par(las=2) # make label text perpendicular to axis
It is written here: http://www.statmethods.net/graphs/bar.html
You can use ggplot2 to rotate the x-axis label adding an additional layer
theme(axis.text.x = element_text(angle = 90, hjust = 1))
In the documentation of Bar Plots we can read about the additional parameters (...) which can be passed to the function call:
... arguments to be passed to/from other methods. For the default method these can
include further arguments (such as axes, asp and main) and graphical
parameters (see par) which are passed to plot.window(), title() and axis.
In the documentation of graphical parameters (documentation of par) we can see:
las
numeric in {0,1,2,3}; the style of axis labels.
0:
always parallel to the axis [default],
1:
always horizontal,
2:
always perpendicular to the axis,
3:
always vertical.
Also supported by mtext. Note that string/character rotation via argument srt to par does not affect the axis labels.
That is why passing las=2 makes the labels perpendicular, although not at 45°.
Andre Silva's answer works great for me, with one caveat in the "barplot" line:
barplot(mtcars$qsec, col="grey50",
main="",
ylab="mtcars - qsec", ylim=c(0,5+max(mtcars$qsec)),
xlab = "",
xaxt = "n",
space=1)
Notice the "xaxt" argument. Without it, the labels are drawn twice, the first time without the 60 degree rotation.
I'm trying to create a figure similar to the one below (taken from Ro, Russell, & Lavie, 2001). In their graph, they are plotting bars for the errors (i.e., accuracy) within the reaction time bars. Basically, what I am looking for is a way to plot bars within bars.
I know there are several challenges with creating a graph like this. First, Hadley points out that it is not possible to create a graph with two scales in ggplot2 because those graphs are fundamentally flawed (see Plot with 2 y axes, one y axis on the left, and another y axis on the right)
Nonetheless, the graph with superimposed bars seems to solve this dual sclaing problem, and I'm trying to figure out a way to create it in R. Any help would be appreciated.
It's fairly easy in base R, by using par(new = T) to add to an existing graph
set.seed(54321) # for reproducibility
data.1 <- sample(1000:2000, 10)
data.2 <- sample(seq(0, 5, 0.1), 10)
# Use xpd = F to avoid plotting the bars below the axis
barplot(data.1, las = 1, col = "black", ylim = c(500, 3000), xpd = F)
par(new = T)
# Plot the new data with a different ylim, but don't plot the axis
barplot(data.2, las = 1, col = "white", ylim = c(0, 30), yaxt = "n")
# Add the axis on the right
axis(4, las = 1)
It is pretty easy to make the bars in ggplot. Here is some example code. No two y-axes though (although look here for a way to do that too).
library(ggplot2)
data.1 <- sample(1000:2000, 10)
data.2 <- sample(500:1000, 10)
library(ggplot2)
ggplot(mapping = aes(x, y)) +
geom_bar(data = data.frame(x = 1:10, y = data.1), width = 0.8, stat = 'identity') +
geom_bar(data = data.frame(x = 1:10, y = data.2), width = 0.4, stat = 'identity', fill = 'white') +
theme_classic() + scale_y_continuous(expand = c(0, 0))
in R, with ecdf I can plot a empirical cumulative distribution function
plot(ecdf(mydata))
and with hist I can plot a histogram of my data
hist(mydata)
How I can plot the histogram and the ecdf in the same plot?
EDIT
I try make something like that
https://mathematica.stackexchange.com/questions/18723/how-do-i-overlay-a-histogram-with-a-plot-of-cdf
Also a bit late, here's another solution that extends #Christoph 's Solution with a second y-Axis.
par(mar = c(5,5,2,5))
set.seed(15)
dt <- rnorm(500, 50, 10)
h <- hist(
dt,
breaks = seq(0, 100, 1),
xlim = c(0,100))
par(new = T)
ec <- ecdf(dt)
plot(x = h$mids, y=ec(h$mids)*max(h$counts), col = rgb(0,0,0,alpha=0), axes=F, xlab=NA, ylab=NA)
lines(x = h$mids, y=ec(h$mids)*max(h$counts), col ='red')
axis(4, at=seq(from = 0, to = max(h$counts), length.out = 11), labels=seq(0, 1, 0.1), col = 'red', col.axis = 'red')
mtext(side = 4, line = 3, 'Cumulative Density', col = 'red')
The trick is the following: You don't add a line to your plot, but plot another plot on top, that's why we need par(new = T). Then you have to add the y-axis later on (otherwise it will be plotted over the y-axis on the left).
Credits go here (#tim_yates Answer) and there.
There are two ways to go about this. One is to ignore the different scales and use relative frequency in your histogram. This results in a harder to read histogram. The second way is to alter the scale of one or the other element.
I suspect this question will soon become interesting to you, particularly #hadley 's answer.
ggplot2 single scale
Here is a solution in ggplot2. I am not sure you will be satisfied with the outcome though because the CDF and histograms (count or relative) are on quite different visual scales. Note this solution has the data in a dataframe called mydata with the desired variable in x.
library(ggplot2)
set.seed(27272)
mydata <- data.frame(x= rexp(333, rate=4) + rnorm(333))
ggplot(mydata, aes(x)) +
stat_ecdf(color="red") +
geom_bar(aes(y = (..count..)/sum(..count..)))
base R multi scale
Here I will rescale the empirical CDF so that instead of a max value of 1, its maximum value is whatever bin has the highest relative frequency.
h <- hist(mydata$x, freq=F)
ec <- ecdf(mydata$x)
lines(x = knots(ec),
y=(1:length(mydata$x))/length(mydata$x) * max(h$density),
col ='red')
you can try a ggplot approach with a second axis
set.seed(15)
a <- rnorm(500, 50, 10)
# calculate ecdf with binsize 30
binsize=30
df <- tibble(x=seq(min(a), max(a), diff(range(a))/binsize)) %>%
bind_cols(Ecdf=with(.,ecdf(a)(x))) %>%
mutate(Ecdf_scaled=Ecdf*max(a))
# plot
ggplot() +
geom_histogram(aes(a), bins = binsize) +
geom_line(data = df, aes(x=x, y=Ecdf_scaled), color=2, size = 2) +
scale_y_continuous(name = "Density",sec.axis = sec_axis(trans = ~./max(a), name = "Ecdf"))
Edit
Since the scaling was wrong I added a second solution, calculatin everything in advance:
binsize=30
a_range= floor(range(a)) +c(0,1)
b <- seq(a_range[1], a_range[2], round(diff(a_range)/binsize)) %>% floor()
df_hist <- tibble(a) %>%
mutate(gr = cut(a,b, labels = floor(b[-1]), include.lowest = T, right = T)) %>%
count(gr) %>%
mutate(gr = as.character(gr) %>% as.numeric())
# calculate ecdf with binsize 30
df <- tibble(x=b) %>%
bind_cols(Ecdf=with(.,ecdf(a)(x))) %>%
mutate(Ecdf_scaled=Ecdf*max(df_hist$n))
ggplot(df_hist, aes(gr, n)) +
geom_col(width = 2, color = "white") +
geom_line(data = df, aes(x=x, y=Ecdf*max(df_hist$n)), color=2, size = 2) +
scale_y_continuous(name = "Density",sec.axis = sec_axis(trans = ~./max(df_hist$n), name = "Ecdf"))
As already pointed out, this is problematic because the plots you want to merge have such different y-scales. You can try
set.seed(15)
mydata<-runif(50)
hist(mydata, freq=F)
lines(ecdf(mydata))
to get
Although a bit late... Another version which is working with preset bins:
set.seed(15)
dt <- rnorm(500, 50, 10)
h <- hist(
dt,
breaks = seq(0, 100, 1),
xlim = c(0,100))
ec <- ecdf(dt)
lines(x = h$mids, y=ec(h$mids)*max(h$counts), col ='red')
lines(x = c(0,100), y=c(1,1)*max(h$counts), col ='red', lty = 3) # indicates 100%
lines(x = c(which.min(abs(ec(h$mids) - 0.9)), which.min(abs(ec(h$mids) - 0.9))), # indicates where 90% is reached
y = c(0, max(h$counts)), col ='black', lty = 3)
(Only the second y-axis is not working yet...)
In addition to previous answers, I wanted to have ggplot do the tedious calculation (in contrast to #Roman's solution, which was kindly enough updated upon my request), i.e., calculate and draw the histogram and calculate and overlay the ECDF. I came up with the following (pseudo code):
# 1. Prepare the plot
plot <- ggplot() + geom_hist(...)
# 2. Get the max value of Y axis as calculated in the previous step
maxPlotY <- max(ggplot_build(plot)$data[[1]]$y)
# 3. Overlay scaled ECDF and add secondary axis
plot +
stat_ecdf(aes(y=..y..*maxPlotY)) +
scale_y_continuous(name = "Density", sec.axis = sec_axis(trans = ~./maxPlotY, name = "ECDF"))
This way you don't need to calculate everything beforehand and feed the results to ggpplot. Just lay back and let it do everything for you!
I am trying to get the x axis labels to be rotated 45 degrees on a barplot with no luck. This is the code I have below:
barplot(((data1[,1] - average)/average) * 100,
srt = 45,
adj = 1,
xpd = TRUE,
names.arg = data1[,2],
col = c("#3CA0D0"),
main = "Best Lift Time to Vertical Drop Ratios of North American Resorts",
ylab = "Normalized Difference",
yaxt = 'n',
cex.names = 0.65,
cex.lab = 0.65)
use optional parameter las=2 .
barplot(mytable,main="Car makes",ylab="Freqency",xlab="make",las=2)
EDITED ANSWER PER DAVID'S RESPONSE:
Here's a kind of hackish way. I'm guessing there's an easier way. But you could suppress the bar labels and the plot text of the labels by saving the bar positions from barplot and do a little tweaking up and down. Here's an example with the mtcars data set:
x <- barplot(table(mtcars$cyl), xaxt="n")
labs <- paste(names(table(mtcars$cyl)), "cylinders")
text(cex=1, x=x-.25, y=-1.25, labs, xpd=TRUE, srt=45)
Rotate the x axis labels with angle equal or smaller than 90 degrees using base graphics. Code adapted from the R FAQ:
par(mar = c(7, 4, 2, 2) + 0.2) #add room for the rotated labels
#use mtcars dataset to produce a barplot with qsec colum information
mtcars = mtcars[with(mtcars, order(-qsec)), ] #order mtcars data set by column "qsec"
end_point = 0.5 + nrow(mtcars) + nrow(mtcars) - 1 #this is the line which does the trick (together with barplot "space = 1" parameter)
barplot(mtcars$qsec, col = "grey50",
main = "",
ylab = "mtcars - qsec", ylim = c(0,5 + max(mtcars$qsec)),
xlab = "",
xaxt = "n", # Do not plot the default labels
space = 1)
#rotate 60 degrees (srt = 60)
text(seq(1.5, end_point, by = 2), par("usr")[3]-0.25,
srt = 60, adj = 1, xpd = TRUE,
labels = paste(rownames(mtcars)), cex = 0.65)
You can simply pass your data frame into the following function:
rotate_x <- function(data, column_to_plot, labels_vec, rot_angle) {
plt <- barplot(data[[column_to_plot]], col='steelblue', xaxt="n")
text(plt, par("usr")[3], labels = labels_vec, srt = rot_angle, adj = c(1.1,1.1), xpd = TRUE, cex=0.6)
}
Usage:
rotate_x(mtcars, 'mpg', row.names(mtcars), 45)
You can change the rotation angle of the labels as needed.
You may use
par(las=2) # make label text perpendicular to axis
It is written here: http://www.statmethods.net/graphs/bar.html
You can use ggplot2 to rotate the x-axis label adding an additional layer
theme(axis.text.x = element_text(angle = 90, hjust = 1))
In the documentation of Bar Plots we can read about the additional parameters (...) which can be passed to the function call:
... arguments to be passed to/from other methods. For the default method these can
include further arguments (such as axes, asp and main) and graphical
parameters (see par) which are passed to plot.window(), title() and axis.
In the documentation of graphical parameters (documentation of par) we can see:
las
numeric in {0,1,2,3}; the style of axis labels.
0:
always parallel to the axis [default],
1:
always horizontal,
2:
always perpendicular to the axis,
3:
always vertical.
Also supported by mtext. Note that string/character rotation via argument srt to par does not affect the axis labels.
That is why passing las=2 makes the labels perpendicular, although not at 45°.
Andre Silva's answer works great for me, with one caveat in the "barplot" line:
barplot(mtcars$qsec, col="grey50",
main="",
ylab="mtcars - qsec", ylim=c(0,5+max(mtcars$qsec)),
xlab = "",
xaxt = "n",
space=1)
Notice the "xaxt" argument. Without it, the labels are drawn twice, the first time without the 60 degree rotation.