Why are my error bars on my graph out of place? - r

I have a graph that I'm trying to make with ggplot and gridExtra, but my error bars are out of place. I want the error bars to be at the top of each bar, not where they are now. What can I do to correct them?
Also, what ggsave parameters will generate a graph with the same pixel parameters that I am using with the r png base function? ggsave seems to work more consistently than this function, so I need to use it.
Data:
###Open packages###
library(readxl)
library(readr)
library(dplyr)
library(tidyr)
library(ggplot2)
library(gridExtra)
#Dataframes
set1 <- data.frame(type = c(1,
1,
1,
1,
1,
1,
1,
1,
1,
2,
2,
2,
2,
2,
2,
2,
2,
2,
3,
3,
3,
3,
3,
3,
3,
3,
3),
flowRate = c(24,
24,
24,
45,
45,
45,
58,
58,
58,
24,
24,
24,
45,
45,
45,
58,
58,
58,
24,
24,
24,
45,
45,
45,
58,
58,
58),
speed = c(0.563120137230256,
0.301721535875508,
0.170683367727845,
0.698874950490133,
0.158488731250147,
0.162788814307903,
0.105943103772245,
0.682354871986346,
0.17945825301837,
0.806637519498752,
0.599304186634932,
0.268788206619179,
0.518615600601962,
0.907628477211427,
0.144209408332705,
0.161586044320138,
0.946354993801663,
0.488881557759483,
0.497120443885793,
0.666120238846602,
0.264813203831783,
0.717007333314455,
0.95119232422312,
0.833669574933742,
0.450082932184122,
0.309570971522678,
0.732874401666482))
set2 <- data.frame(type = c(1,
1,
1,
1,
1,
1,
1,
1,
1,
2,
2,
2,
2,
2,
2,
2,
2,
2,
3,
3,
3,
3,
3,
3,
3,
3,
3),
flowRate = c(24,
24,
24,
45,
45,
45,
58,
58,
58,
24,
24,
24,
45,
45,
45,
58,
58,
58,
24,
24,
24,
45,
45,
45,
58,
58,
58),
speed = c(0.489966876244169,
0.535542121502899,
0.265940150225231,
0.399521957817437,
0.0831661276630631,
0.302201301891001,
0.78194419406759,
0.202331797255324,
0.192182716686147,
0.163038660094618,
0.658020173938572,
0.735633308902771,
0.480982144690572,
0.749452781972296,
0.491759702396918,
0.459610541236644,
0.397660083986082,
0.939983924945833,
0.128956722185581,
0.998492083119223,
0.440514184126494,
0.242917958355044,
0.350643319960552,
0.02613674288471,
0.71625407018877,
0.589325978787179,
0.649116781211748))
Code:
#Standard error of the mean function
sem <- function(x) sd(x)/sqrt(length(x))
#Aggregate dataframes, mean and Standard Error
mean_set1 <- aggregate(set1, by=list(set1$flowRate, set1$speed), mean)
mean_set1 <- select(mean_set1, -Group.1, -Group.2)
mean_set1 <- arrange(mean_set1, type, flowRate)
sem_set1 <- aggregate(set1, by=list(set1$flowRate, set1$speed), sem)
sem_set1 <- as.data.frame(sem_set1)
sem_set1 <- cbind(mean_set1$type, mean_set1$flowRate, sem_set1$Group.2)
sem_set1 <- as.data.frame(sem_set1)
mean_set2 <- aggregate(set2, by=list(set2$flowRate, set2$speed), mean)
mean_set2 <- select(mean_set2, -Group.1, -Group.2)
mean_set2 <- arrange(mean_set2, type, flowRate)
sem_set2 <- aggregate(set2, by=list(set2$flowRate, set2$speed), sem)
sem_set2 <- as.data.frame(sem_set2)
sem_set2 <- cbind(mean_set2$type, mean_set2$flowRate, sem_set2$Group.2)
sem_set2 <- as.data.frame(sem_set2)
#Graph sets
set1_graph <- ggplot(mean_set1, aes(x=type, y=speed, fill=factor(flowRate)))+
geom_bar(stat="identity",width=0.6, position="dodge", col="black")+
scale_fill_discrete(name="Flow Rate")+
xlab("type")+ylab("Speed")+
geom_errorbar(aes(ymin= mean_set1$speed,ymax=mean_set1$speed+sem_set1$V3), width=0.2, position = position_dodge(0.6))
set2_graph <- ggplot(mean_set2, aes(x=type, y=speed, fill=factor(flowRate)))+
geom_bar(stat="identity",width=0.6, position="dodge", col="black")+
scale_fill_discrete(name="Speed")+
xlab("type")+ylab("Flow Rate")+
geom_errorbar(aes(ymin= mean_set2$speed,ymax=mean_set2$speed+sem_set2$V3), width=0.2, position = position_dodge(0.6))
#Grid.arrange and save image
png("image.png", width = 1000, height = 700)
grid.arrange(set1_graph, set2_graph,nrow=1, ncol=2)
dev.off()

Related

Interpolating three columns

I have a set of data in ranges like:
x|y|z
-4|1|45
-4|2|68
-4|3|96
-2|1|56
-2|2|65
-2|3|89
0|1|45
0|2|56
0|3|75
2|1|23
2|2|56
2|3|75
4|1|42
4|2|65
4|3|78
Here I need to interpolate between x and y using the z value.
I tried interpolating separately for x and y using z value by using the below code:
interpol<-approx(x,z,method="linear")
interpol_1<-approx(y,z,method="linear")
Now I'm trying to use all the three columns but values are coming wrong.
In your script you forgot to direct to your data.frame. Note the use of $ in the approx function.
interpol <- approx(df$x,df$z,method="linear")
interpol_1 <- approx(df$y,df$z,method="linear")
Data:
df <- data.frame(
x = c(-4, -4, -4, -2, -2, -2, 0, 0, 0, 2, 2, 2, 4, 4, 4),
y = c(1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3),
z = c(45, 68, 96, 56, 65, 89, 45, 56, 75, 23, 56, 75, 42, 65, 78)
)

Specialised Boxplot: Plotting Lines to the Error Bars to Highlight the Data Range in R

Overview
I have a data frame called ANOVA.Dataframe.1 (see below) containing the dependent variable called 'Canopy_Index', and the independent variable called 'Urbanisation_index".
My aim is to produce a boxplot (exactly the same as the desired result below) for Canopy Cover (%) for each category of the Urbanisation Index with plotted lines pointing towards both the bottom and top of the error bars to highlight the data range.
I have searched intensively in order to find the code to produce the desired boxplot this (please see the desired result), but I was unsuccessful, and I'm also unsure if these boxplots have a specialised name.
Perhaps this can be achieved in either ggplot or Base R
If anyone can help, I would be deeply appreciative.
Desired Result ( Reference)
I can produce an ordinary boxplot with the R-code below, but I cannot figure out how to implement the lines pointing towards the ends of the error bars.
R-code
Boxplot.obs1.Canopy.Urban<-boxplot(ANOVA.Dataframe.1$Canopy_Index~ANOVA.Dataframe.1$Urbanisation_index,
main="Mean Canopy Index (%) for Categories of the Urbansiation Index",
xlab="Urbanisation Index",
ylab="Canopy Index (%)")
Boxplot produced from R-code
Data frame 1
structure(list(Urbanisation_index = c(2, 2, 4, 4, 3, 3, 4, 4,
4, 2, 4, 3, 4, 4, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2,
2, 2, 2, 4, 4, 3, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 1, 4, 4, 4,
4, 4, 4, 4), Canopy_Index = c(65, 75, 55, 85, 85, 85, 95, 85,
85, 45, 65, 75, 75, 65, 35, 75, 65, 85, 65, 95, 75, 75, 75, 65,
75, 65, 75, 95, 95, 85, 85, 85, 75, 75, 65, 85, 75, 65, 55, 95,
95, 95, 95, 45, 55, 35, 55, 65, 95, 95, 45, 65, 45, 55)), row.names = c(NA,
-54L), class = "data.frame")
Dataframe 2
structure(list(Urbanisation_index = c(2, 2, 4, 4, 3, 3, 4, 4,
4, 3, 4, 4, 4, 4, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2,
2, 2, 2, 4, 4, 3, 2, 2, 2, 2, 2, 2, 1, 1, 4, 4, 4, 4, 4, 4, 4
), Canopy_Index = c(5, 45, 5, 5, 5, 5, 45, 45, 55, 15, 35, 45,
5, 5, 5, 5, 5, 5, 35, 15, 15, 25, 25, 5, 5, 5, 5, 5, 5, 15, 25,
15, 35, 25, 45, 5, 25, 5, 5, 5, 5, 55, 55, 15, 5, 25, 15, 15,
15, 15)), row.names = c(NA, -50L), class = "data.frame")
Alice, is this what you are looking for?
You can do everything with ggplot2, but for non standard things you have to play with it for a while. My code:
library(tidyverse)
library(wrapr)
df %.>%
ggplot(data = ., aes(
x = Urbanisation_index,
y = Canopy_Index,
group = Urbanisation_index
)) +
stat_boxplot(
geom = 'errorbar',
width = .25
) +
geom_boxplot() +
geom_line(
data = group_by(., Urbanisation_index) %>%
summarise(
bot = min(Canopy_Index),
top = max(Canopy_Index)
) %>%
gather(pos, val, bot:top) %>%
select(
x = Urbanisation_index,
y = val
) %>%
mutate(gr = row_number()) %>%
bind_rows(
tibble(
x = 0,
y = max(.$y) * 1.15,
gr = 1:8
)
),
aes(
x = x,
y = y,
group = gr
)) +
theme_light() +
theme(panel.grid = element_blank()) +
coord_cartesian(
xlim = c(min(.$Urbanisation_index) - .5, max(.$Urbanisation_index) + .5),
ylim = c(min(.$Canopy_Index) * .95, max(.$Canopy_Index) * 1.05)
) +
ylab('Company Index (%)') +
xlab('Urbanisation Index')

Merge and Perfectly Align Histogram and Boxplot using ggplot2

since yesterday I am reading answers and websites in order to combine and align in one plot an histogram and a boxplot generated using ggplot2 package.
This question differs from others because the boxplot chart needs to be reduced in height and aligned to the left outer margin of the histogram.
Considering the following dataset:
my_df <- structure(list(id = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,
76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
92, 93, 94, 95, 96, 97, 98, 99, 100), value= c(18, 9, 3,
4, 3, 13, 12, 5, 8, 37, 64, 107, 11, 11, 8, 18, 5, 13, 13, 14,
11, 11, 9, 14, 11, 14, 12, 10, 11, 10, 5, 3, 8, 11, 12, 11, 7,
6, 6, 4, 11, 8, 14, 13, 14, 15, 10, 2, 4, 4, 8, 15, 21, 9, 5,
7, 11, 6, 11, 2, 6, 16, 5, 11, 21, 33, 12, 10, 13, 33, 35, 7,
7, 9, 2, 21, 32, 19, 9, 8, 3, 26, 37, 5, 6, 10, 18, 5, 70, 48,
30, 10, 15, 18, 7, 4, 19, 10, 4, 32)), row.names = c(NA, 100L
), class = "data.frame", .Names = c("id", "value"))
I generated the boxplot:
require(dplyr)
require(ggplot2)
my_df %>% select(value) %>%
ggplot(aes(x="", y = value)) +
geom_boxplot(fill = "lightblue", color = "black") +
coord_flip() +
theme_classic() +
xlab("") +
theme(axis.text.y=element_blank(),
axis.ticks.y=element_blank())
and I generated the histogram
my_df %>% select(id, value) %>%
ggplot() +
geom_histogram(aes(x = value, y = (..count..)/sum(..count..)),
position = "identity", binwidth = 1,
fill = "lightblue", color = "black") +
ylab("Relative Frequency") +
theme_classic()
The result I am looking to obtain is a single plot like:
Note that the boxplot must be reduced in height and the ticks must be exactly aligned in order to give a different perspective of the same visual.
You can use either egg, cowplot or patchwork packages to combine those two plots. See also this answer for more complex examples.
library(dplyr)
library(ggplot2)
plt1 <- my_df %>% select(value) %>%
ggplot(aes(x="", y = value)) +
geom_boxplot(fill = "lightblue", color = "black") +
coord_flip() +
theme_classic() +
xlab("") +
theme(axis.text.y=element_blank(),
axis.ticks.y=element_blank())
plt2 <- my_df %>% select(id, value) %>%
ggplot() +
geom_histogram(aes(x = value, y = (..count..)/sum(..count..)),
position = "identity", binwidth = 1,
fill = "lightblue", color = "black") +
ylab("Relative Frequency") +
theme_classic()
egg
# install.packages("egg", dependencies = TRUE)
egg::ggarrange(plt2, plt1, heights = 2:1)
cowplot
# install.packages("cowplot", dependencies = TRUE)
cowplot::plot_grid(plt2, plt1,
ncol = 1, rel_heights = c(2, 1),
align = 'v', axis = 'lr')
patchwork
# install.packages("devtools", dependencies = TRUE)
# devtools::install_github("thomasp85/patchwork")
library(patchwork)
plt2 + plt1 + plot_layout(nrow = 2, heights = c(2, 1))

Order by y-Value in Facet Plot

Consider the following data.frame
RANK_GROUP <- as.factor(c(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1))
CHANNEL_CATEGORY <- as.factor(c(1, 2, 10, 15, 17, 19, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 43, 44, 1, 2, 10, 15, 17, 19, 20, 22, 23, 24, 25, 26, 27, 28, 29, 43))
CATEGORY_COUNT <- c(105, 23, 417, 10, 58, 6, 535, 211, 215, 465, 28, 273, 70, 47, 7,1,21,3,69, 14, 493, 3, 44, 3, 516, 162, 253, 516, 24, 228, 64, 59, 2, 45)
data <- data.frame(RANK_GROUP, CHANNEL_CATEGORY,CATEGORY_COUNT)
I want to make a Facet-Plot with a barplot for each distribution:
ggplot(data = data) +
aes(x=CHANNEL_CATEGORY, y = CATEGORY_COUNT) +
geom_bar(stat="identity", position ="dodge", colour="black") +
facet_grid(. ~ RANK_GROUP)
How can I order the plots according to their y-value withing each facet-plot?
took the help of cookbook,
library(dplyr)
pd <- data %>%
group_by(RANK_GROUP) %>%
top_n(nrow(data), abs(CATEGORY_COUNT)) %>%
ungroup() %>%
arrange(RANK_GROUP, CATEGORY_COUNT) %>%
mutate(order = row_number())
pd$order <- as.factor(pd$order)
ggplot(data = pd) +
aes(x=order, y = CATEGORY_COUNT) +
geom_bar(stat="identity", position ="dodge", colour="black") +
facet_grid(. ~ RANK_GROUP)+
scale_x_discrete(labels = CHANNEL_CATEGORY , breaks = order)+
theme(axis.text.x = element_text(angle = 60, hjust = .5, size = 8)) +
labs(x="Channel")

Optimizing add_trace() in a for loop?

I'm using the add_trace() function in a for loop to create lines for a 3d network graph in plotly's scatter3d mode. Each add_trace draws an individual line between two nodes in the network. The method is working, but with large number of loops, the speed of the individual loops seems to be slowing down very quickly.
Example data can be downloaded here: https://gist.github.com/pravj/9168fe52823c1702a07b
library(igraph)
library(plotly)
G <- read.graph("karate.gml", format = c("gml"))
L <- layout.circle(G)
vs <- V(G)
es <- as.data.frame(get.edgelist(G))
Nv <- length(vs)
Ne <- length(es[1]$V1)
Xn <- L[,1]
Yn <- L[,2]
network <- plot_ly(type = "scatter3d", x = Xn, y = Yn, z = rep(0, Ne), mode = "markers", text = vs$label, hoverinfo = "text", showlegend = F)
for(i in 1:Ne) {
v0 <- es[i,]$V1
v1 <- es[i,]$V2
x0 <- Xn[v0]
y0 <- Yn[v0]
x1 <- Xn[v1]
y1 <- Yn[v1]
df <- data.frame(x = c(x0, x1), y = c(y0, y1), z = c(0, 0))
network <- add_trace(network, data = df, x = x, y = y, z = z, type = "scatter3d", mode = "lines", showlegend = F,
marker = list(color = '#030303'), line = list(width = 0.5))
}
This example is fairly quick, but when I include a few hundred edges or more, the execution of the individual loops start to slow down radically. I tried different optimization methods (vectorisation etc), but there seems to be no working around the slowness of the add_trace function itself.
Any suggestions?
The most efficient way to add many line segments in plotly is not as a separate trace each, but to use only a single trace that contains all the line segments. You can do this by constructing a data frame with the x,y coordinates of each node to be connected, interspersed with NA's between each line segment. Then use connectgaps=FALSE to break the trace into separate segments at each NA. You can see another example of this approach, applied to spaghetti plots in this answer.
es$breaks <- NA
lines <- data.frame(node=as.vector(t(es)), x=NA, y=NA, z=0)
lines[which(!is.na(lines$node)),]$x <- Xn[lines[which(!is.na(lines$node)),]$node]
lines[which(!is.na(lines$node)),]$y <- Yn[lines[which(!is.na(lines$node)),]$node]
network <- plot_ly(type = "scatter3d", x = Xn, y = Yn, z = rep(0, Ne),
mode = "markers", text = vs$label, hoverinfo = "text",
showlegend = F) %>%
add_trace(data=lines, x=x, y=y, z=z, showlegend = FALSE,
type = 'scatter3d', mode = 'lines+markers',
marker = list(color = '#030303'), line = list(width = 0.5),
connectgaps=FALSE)
Reproducible data for this question
For convenience, here are the data for this question. The OP required downloading a .gml file from github, and installing library(igraph) to process the data into these.
es <- structure(list(
V1 = c(1, 1, 2, 1, 2, 3, 1, 1, 1, 5, 6, 1, 2, 3, 4, 1, 3, 3, 1, 5, 6, 1, 1, 4, 1, 2, 3, 4, 6, 7, 1, 2, 1, 2,
1, 2, 24, 25, 3, 24, 25, 3, 24, 27, 2, 9, 1, 25, 26, 29, 3, 9, 15, 16, 19, 21, 23, 24, 30, 31, 32, 9, 10, 14, 15, 16, 19, 20,
21, 23, 24, 27, 28, 29, 30, 31, 32, 33),
V2 = c(2, 3, 3, 4, 4, 4, 5, 6, 7, 7, 7, 8, 8, 8, 8, 9, 9, 10, 11, 11, 11, 12, 13, 13,
14, 14, 14, 14, 17, 17, 18, 18, 20, 20, 22, 22, 26, 26, 28, 28, 28, 29, 30, 30, 31, 31, 32, 32, 32, 32, 33, 33, 33, 33, 33, 33,
33, 33, 33, 33, 33, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34)),
.Names = c("V1", "V2"), row.names = c(NA, -78L), class = "data.frame")
theta <- seq(0,2,length.out=35)[1:34]
Xn <- cospi(theta)
Yn <- sinpi(theta)
Nv <- NROW(Xn)
Ne <- NROW(es)
vs <- data.frame(label = as.character(1:Nv))

Resources