I have the next code, where I have negative positive and negative values and I want to put the positive values above the edge of bar, and negative values below the edge of the bar. I want to know too how to change the y axes (limites), changes the order of "Flujo" and how to change background graph.
tabla <-
Flujo Mes Valor
1 Qns Septiembre 79.4
2 Qnl Septiembre -97.5
3 Qh Septiembre -3.1
4 Qe Septiembre -11.3
5 Qr Septiembre 0.5
6 Qg Septiembre 16.5
7 Qm Septiembre 15.5
8 Qns Octubre 79.1
9 Qnl Octubre -87.8
10 Qh Octubre -0.8
11 Qe Octubre -1.7
12 Qr Octubre 0.0
13 Qg Octubre 36.0
14 Qm Octubre -57.9
tabla<-data.frame("Flujo"=c("Qns","Qnl","Qh","Qe","Qr","Qg","Qm","Qns","Qnl","Qh","Qe","Qr","Qg","Qm"),
"Mes"= rbind(array(" Septiembre", dim=c(7,1)) , array("Octubre", dim=c(7,1))) ,
"Valor"=round(c(s1$Qns,s1$Qnl,s1$Qh,s1$Qe,s1$Qr,s1$Qg,s1$Qm,s2$Qns,s2$Qnl,s2$Qh,s2$Qe,s2$Qr,s2$Qg,s2$Qm),digits=1))
colors <-c("Qns"="red","Qnl"="blue","Qh"="deeppink","Qe"="darkgoldenrod1","Qr"="darkblue","Qg"="green","Qm"="brown")
fig31 <- ggplot(data=tabla, aes(x=Mes, y=Valor,fill=Flujo)) +
geom_bar(stat="identity", color="black", position=position_dodge())+
theme_minimal()+
geom_text(aes(label=Valor),position=position_dodge(width=0.9),size=4, vjust=1.5)+
scale_fill_manual(values = colors) +
theme_light()
fig31
Here is one way you could do: I changed geom_bar with geom_col anc put an ifelse in geom_text(). Here you can define the position 0,-1,1.5` of the numbers.
fig31 <- ggplot(tabla, aes(Mes, Valor, fill=Flujo)) +
geom_col(position = position_dodge()) +
geom_text(aes(label = paste(Valor)),
position=position_dodge(width=0.9),size=3,
vjust = ifelse(tabla$Valor >= 0, -1, 1.5)) +
scale_fill_manual(values = colors) +
theme_light()
fig31
Related
I created a ggplot function to plot groups of data given below (I am sorry, I do not know how to post the data file)
There are three problems with this graph:
1.The Y-axis title has a superscripted character. Because of this, it cannot be bolded (the same formatting for the x-axis title works)
2.The Legend title is defined as "Group ID". But the code is using the Column Title "GroupID" ignoring the definition. (The code line "scale_fill_discrete("Group ID")" supposed to set the legend title).
3.The width of error bars is not constant, it is changing from point to point (easily noticeable for the green ones)
I appreciate any help to fix these issues.
Code:
library(ggplot2)
# Colors
Mycolors<- c("blue", "red", "green", "cyan", "orange", "brown", "magenta", "grey", "black")
# Shapes
Myshapes<-c(15:25,0:2)
# Plot position
Mypd <- position_dodge(width = 0.2)
# Read data
mData<-read.csv("F:/user/documents/R/Notebooks/Ggplot/TestData.csv")
pAllGroupData<-function(mData, xLabel, yLabel, gTitle, sTitle, sCaption, yType, gErrType) {
v <- mData$dMean
x <- mData$DayNum
p <- ggplot(data = mData, mapping = aes(x = x, y = v, color = GroupID, shape = GroupID))
p <- p + geom_line(position = Mypd) +
geom_point(position = Mypd, size = 4)
# Plot errorbars
if (gErrType == "StdErr") {
p<- p + geom_errorbar(aes(x = x, ymin = v - mData$dStdErr, ymax = v + mData$dStdErr), width=1.5, position=Mypd)
} else if (gErrType == "StdDev") {
p<- p + geom_errorbar(aes(x = x, ymin = v - mData$dStdDev, ymax = v + mData$dStdDev), width=1.5, position=Mypd)
} else if (gErrType == "IQR") {
p<- p + geom_errorbar(aes(x = x, ymin = v - mData$dIQR, ymax = v + mData$dIQR), width=1.5, position=Mypd)
}
# Turn Y axis logarithmic and place log ticks
if (yType == "Log") {
p<- p + ylim (1, vMax) + # This is to avoid log(0)
coord_trans(y = "log10") +
annotation_logticks(sides = "lr", scaled=FALSE) # ticks are only left and right y axes
}
# Plot the graph with theme
p <- p +
labs(x = xLabel, y = yLabel, title = gTitle, subtitle = sTitle, caption = sCaption) +
# Include origine (0, 0)
expand_limits(x = 0, y = 0) +
# Custom Colors
scale_colour_manual(values = Mycolors) +
# Custom Shapes
scale_shape_manual(values = Myshapes) +
# Legend Title (not working!)
scale_fill_discrete("Group ID")
p <- p + gTheme(p)
return(p)
}
# Test
p<-pAllGroupData(mData, xLabel = "Days", yLabel = bquote("Volume "~(mm^3)), gTitle = "Study", sTitle = "X", sCaption = "SCaption", yType = "Lin", gErrType = "StdDev")
p
Data:
GroupID DayNum n dMean dMedian dStdDev dStdErr dIQR
Grp1 13 8 207.03 211.45 13.04 4.61 11.73
Grp1 15 8 288.15 274.40 48.98 17.32 33.25
Grp1 18 8 393.50 381.15 63.63 22.50 52.98
Grp1 21 8 507.63 499.80 73.06 25.83 80.88
Grp1 26 8 636.14 614.65 112.53 39.79 206.53
Grp2 13 8 207.05 205.25 41.00 14.50 72.35
Grp2 15 8 142.76 145.60 27.87 9.85 33.70
Grp2 18 8 77.55 82.55 19.44 6.87 22.88
Grp2 21 8 66.38 69.85 20.56 7.27 23.00
Grp2 26 8 67.05 64.20 29.02 10.26 25.48
Grp2 29 8 66.48 63.85 25.95 9.17 19.38
Grp2 33 8 76.96 74.25 25.31 8.95 28.60
Grp3 13 8 207.94 219.65 34.42 12.17 47.18
Grp3 15 8 149.56 155.25 45.74 16.17 70.68
Grp3 18 8 134.83 128.00 59.10 20.90 66.20
Grp3 21 8 164.99 159.40 67.86 23.99 93.63
Grp3 26 8 149.53 160.05 62.48 22.09 100.58
Grp3 29 8 162.21 184.25 61.21 21.64 113.33
Grp3 33 8 177.19 184.00 68.99 24.39 110.35
Grp3 36 8 192.13 160.25 94.93 33.56 122.30
It is advisable to split your question in several posts when you have several problems. Meanwhile here is my attempt to help you:
Problem 1
Replace yLabel = bquote("Volume "~(mm^3)) with yLabel = bquote(bold("Volume " ~ (mm ^ 3))) (note the bold). Kind reminder that this problem was addressed in the past here and also here
Problem 2
You do not use any fill aesthetic, so remove scale_fill_discrete("Group ID"), which has no effect and for each of your aesthetics that you actually use (color and shape), in scale_colour_manual and scale_shape_manual add name = "Group ID" (the desired title of your legend):
scale_colour_manual(name = "Group ID", values = Mycolors) +
scale_shape_manual(name = "Group ID", values = Myshapes)
Problem 3
This seems to have been reported as an issue by some on GitHub, here (the link includes a solution as well)
Similar questions on SO: ggplot2 position_dodge affects error bar width and Width of error bars in ggplot2, both having some answers that you can explore with.
So, you should scale the width of the error bar to the number of row counts for each DayNum. So create a new column in your data.frame, say width like this:
library(dplyr)
mData <- mData %>%
group_by(DayNum) %>%
mutate(width = 1.5 * n())
Then you will have to map this column into the width aesthetic of ggplot while you delete any width attribute from geom_errorbar.
Here is an working example with your data, covering all the 3 problems.
Your data:
mData <- read.table(
text = "
GroupID DayNum n dMean dMedian dStdDev dStdErr dIQR
Grp1 13 8 207.03 211.45 13.04 4.61 11.73
Grp1 15 8 288.15 274.40 48.98 17.32 33.25
Grp1 18 8 393.50 381.15 63.63 22.50 52.98
Grp1 21 8 507.63 499.80 73.06 25.83 80.88
Grp1 26 8 636.14 614.65 112.53 39.79 206.53
Grp2 13 8 207.05 205.25 41.00 14.50 72.35
Grp2 15 8 142.76 145.60 27.87 9.85 33.70
Grp2 18 8 77.55 82.55 19.44 6.87 22.88
Grp2 21 8 66.38 69.85 20.56 7.27 23.00
Grp2 26 8 67.05 64.20 29.02 10.26 25.48
Grp2 29 8 66.48 63.85 25.95 9.17 19.38
Grp2 33 8 76.96 74.25 25.31 8.95 28.60
Grp3 13 8 207.94 219.65 34.42 12.17 47.18
Grp3 15 8 149.56 155.25 45.74 16.17 70.68
Grp3 18 8 134.83 128.00 59.10 20.90 66.20
Grp3 21 8 164.99 159.40 67.86 23.99 93.63
Grp3 26 8 149.53 160.05 62.48 22.09 100.58
Grp3 29 8 162.21 184.25 61.21 21.64 113.33
Grp3 33 8 177.19 184.00 68.99 24.39 110.35
Grp3 36 8 192.13 160.25 94.93 33.56 122.30",
header = TRUE
)
An working example:
library(dplyr)
library(ggplot2)
# Solves Problem 3 - create helper column width
mData <- mData %>%
group_by(DayNum) %>%
mutate(width = 1.5 * n())
Mypd <- position_dodge(width = 0.2)
ggplot(data = mData,
mapping = aes(x = DayNum,
y = dMean,
color = GroupID,
shape = GroupID,
width = width)) + # map width column to width aesthetic
geom_line(position = Mypd) +
geom_point(position = Mypd,
size = 2) +
# width is inherited from the above mapping, no need to map it again
geom_errorbar(aes(ymin = dMean - mData$dStdDev,
ymax = dMean + mData$dStdDev),
position = Mypd) +
labs(y = bquote(bold("Volume " ~ (mm ^ 3)))) + # Solves Problem 1
# Solves Problem 2:
scale_colour_manual(name = "Group ID", values = c("Grp1" = "blue",
"Grp2" = "red",
"Grp3" = "green")) +
scale_shape_manual(name = "Group ID", values = c("Grp1" = 15,
"Grp2" = 16,
"Grp3" = 17)) +
theme_bw()
I want to add the mean values to my basic boxplot and found this function here.
fun_mean <- function(x){
return(data.frame(y=mean(x),label=mean(x,na.rm=T)))
}
I used it within my code, but because I have two factors, it is not working properly. Where do I have to add the second factor?
FixationT2.plot = ggplot(dataT2fix_figs,
aes(x = length, y = perc_fixated, fill = mask)) +
geom_boxplot() +
coord_cartesian (ylim =c(35, 100)) +
geom_hline(yintercept = 50) +
stat_summary(fun.y = mean, geom="point", colour="darkred", size=3) +
labs(title="") +
xlab("Länge Wort N+1") +
ylab("Fixationswahrscheinlichkeit in %\n von Wort N+1") +
guides(fill=guide_legend(title="Preview Maske"))
This is what the data looks like
Subject length mask perc_fixated
<fct> <fct> <fct> <dbl>
1 1 "kurzes\n N+1" keine Maske 41.7
2 1 "kurzes\n N+1" syntaktisch korrekt 91.7
3 1 "kurzes\n N+1" syntaktisch inkorrekt 86.7
4 1 "langes \nN+1" keine Maske 100
5 1 "langes \nN+1" syntaktisch korrekt 87.5
6 1 "langes \nN+1" syntaktisch inkorrekt 91.7
7 2 "kurzes\n N+1" keine Maske 73.3
8 2 "kurzes\n N+1" syntaktisch korrekt 84.6
9 2 "kurzes\n N+1" syntaktisch inkorrekt 83.3
10 2 "langes \nN+1" keine Maske 83.3
You can specify the dodge width for the calculated mean value layer. Right now they appear to be overlapping one another at each x-axis value. I don't see the function you mentioned (fun_mean) actually used in the ggplot code, but it shouldn't really be necessary.
Try this:
ggplot(df,
aes(x = length, y = perc_fixated, fill = mask)) +
geom_boxplot() +
stat_summary(fun.y = mean, geom="point", colour="darkred", size=3,
position = position_dodge2(width = 0.75))
# ... code for axis titles & so on omitted for brevity.
I used width = 0.75 above, because this is the default width for geom_boxplot() / stat_boxplot() (as found in the ggplot2 code here). If you specify a width explicitly in your boxplot, use that instead.
Data used:
df <- read.table(header = TRUE,
text = 'Subject length mask perc_fixated
1 1 "kurzes\n N+1" "keine Maske" 41.7
2 1 "kurzes\n N+1" "syntaktisch korrekt" 91.7
3 1 "kurzes\n N+1" "syntaktisch inkorrekt" 86.7
4 1 "langes \nN+1" "keine Maske" 100
5 1 "langes \nN+1" "syntaktisch korrekt" 87.5
6 1 "langes \nN+1" "syntaktisch inkorrekt" 91.7
7 2 "kurzes\n N+1" "keine Maske" 73.3
8 2 "kurzes\n N+1" "syntaktisch korrekt" 84.6
9 2 "kurzes\n N+1" "syntaktisch inkorrekt" 83.3
10 2 "langes \nN+1" "keine Maske" 83.3')
df$Subject <- factor(df$Subject)
(Next time, please use dput() as advised in the comments to provide your data.)
I have in the past just used the points() function to add mean to my box plots like this:
boxplot(mtcars$mpg ~ mtcars$cyl)
points(x = c(1, 2, 3),
y = tapply(mtcars$mpg, mtcars$cyl, "mean"), col = "red")
So you plot a boxplot then calculate the mean for each of your boxes and plot them as the y argument in points and the x is just a sequence with length how ever many boxes you have.
I am trying to add a line plot to my box plot, on secondary y axis, but i am not able to. what to do? Please help
code for my box plot are:
library(ggplot2)
mydata<-read.csv("boxplot2.csv")
mydata$Class <- factor(mydata$Class,labels = c("1", "2", "3", "4", "5", "6"))
p10 <- ggplot(mydata, aes(x = mydata$Class, y = log(mydata$erosion))) +
geom_boxplot()
p10
p10 <- p10 +
scale_x_discrete(name = "Mean Annual Precipitation(mm/yr)") +
scale_y_continuous(name = "Log Average Erosion Rate(m/My)")
p10 <- ggplot(mydata, aes(x = mydata$Class, y = log(mydata$erosion))) +
geom_boxplot(varwidth=TRUE)
p10 <- p10 +
scale_x_discrete(name = "Mean Annual Precipitation(mm/yr)") +
scale_y_continuous(name = "Log Average Erosion Rate(m/My)")
I want similar figure, but instead of histograms, i will have box plot
add sample data
% Vegetation erosion Class
0 0.43 1
0 0.81 1
2 0.26 1
3 1.05 1
3 0.97 1
12.76 15.97 2
12.84 17.69 2
11.01 14.76 2
13.44 17.94 2
10.76 10.65 2
7.28 67.47 2
23 120.4 3
21 298.63 3
52 21.4 3
9 64.94 3
50 291.88 3
16 493.98 3
11 183.45 3
You just have to specify different aesthetics for the geom_line, something like this:
ggplot(iris,aes(x=Species, y=Sepal.Length, fill=Species)) +
geom_boxplot() +
geom_line(aes(x=Species, y=Petal.Length, group=1), stat = "summary", fun.y="mean") +
scale_y_continuous(sec.axis = sec_axis(~.))
I want to get the hexadecimal codes of the colors that the scale_fill_grey function uses to fill the categories of the barplot produced by the following codes:
library(ggplot2)
data <- data.frame(
Meal = factor(c("Breakfast","Lunch","Dinner","Snacks"),
levels=c("Breakfast","Lunch","Dinner","Snacks")),
Cost = c(9.75,13,19,10.20))
ggplot(data=data, aes(x=Meal, y=Cost, fill=Meal)) +
geom_bar(stat="identity") +
scale_fill_grey(start=0.8, end=0.2)
scale_fill_grey() uses grey_pal() from the scales package, which in turn uses grey.colors(). So, you can generate the codes for the scale of four colours that you used as follows:
grey.colors(4, start = 0.8, end = 0.2)
## [1] "#CCCCCC" "#ABABAB" "#818181" "#333333"
This shows a plot with the colours
image(1:4, 1, matrix(1:4), col = grey.colors(4, start = 0.8, end = 0.2))
Using ggplot_build() function:
#assign ggplot to a variable
myplot <- ggplot(data=data, aes(x=Meal, y=Cost, fill=Meal)) +
geom_bar(stat="identity") +
scale_fill_grey(start=0.8, end=0.2)
#get build
myplotBuild <- ggplot_build(myplot)
#see colours
myplotBuild$data
# [[1]]
# fill x y PANEL group ymin ymax xmin xmax colour size linetype alpha
# 1 #CCCCCC 1 9.75 1 1 0 9.75 0.55 1.45 NA 0.5 1 NA
# 2 #ABABAB 2 13.00 1 2 0 13.00 1.55 2.45 NA 0.5 1 NA
# 3 #818181 3 19.00 1 3 0 19.00 2.55 3.45 NA 0.5 1 NA
# 4 #333333 4 10.20 1 4 0 10.20 3.55 4.45 NA 0.5 1 NA
I'm plotting a stacked bar graph and use geom_text to insert the value of each stack. The difficulty I'm facing is that some stacks are very small/narrow, so that the text of two stacks overlap each other and hence is not very readable. I would like to adjust the text positioning in a way that for example the text position alternates between hjust == 1 and hjust == -1 for each stack, so that there will be no overlaps (or any other method that will result in readable text).
Here's an example of what I'm currently doing (a dput of mydf is provided below):
library(ggplot2)
ggplot(mydf, aes(x=variable, y = value, fill = Category)) +
geom_bar(stat="identity") +
geom_text(aes(label = value, y = pos-(value/2)), size = 3)
What I tried so far is:
Using position = position_dodge(width = 0.5) and position = position_jitter(h =0.5, w = 0.5) but none resulted in what I was trying to do.
My first thought was to define hjust = c(1,-1) hoping that it would be recycled and texts would alternate between hjust == 1 and hjust == -1 but it results in the error message:
Error: Incompatible lengths for set aesthetics: size, hjust
I also tried defining size = c(3,3,3,3,3,3,3,3,3), hjust = c(1,-1,1,-1,1,-1,1,-1,1) but this results in the same error message.
I would appreciate some advice on how to achieve this the right way (and I'm open to other suggestions as well).
I couldn't figure out why the dput didn't work (also for me it didn't), so here's the data in readable format:
Category variable value pos maxpos
1 AX WW 47.8 47.8 184.1
2 AY WW 5.6 53.4 184.1
3 AZ WW 15.8 69.2 184.1
4 BX WW 31.4 100.6 184.1
5 BY WW 11.7 112.3 184.1
6 BZ WW 10.7 123.0 184.1
7 CX WW 2.2 125.2 184.1
8 CY WW 21.4 146.6 184.1
9 CZ WW 37.5 184.1 184.1
10 AX SM 39.8 39.8 148.6
11 AY SM 2.9 42.7 148.6
12 AZ SM 13.2 55.9 148.6
13 BX SM 22.7 78.6 148.6
14 BY SM 7.3 85.9 148.6
15 BZ SM 8.9 94.8 148.6
16 CX SM 1.6 96.4 148.6
17 CY SM 17.3 113.7 148.6
18 CZ SM 34.9 148.6 148.6
19 AX AsIs 156.9 156.9 519.0
20 AY AsIs 13.1 170.0 519.0
21 AZ AsIs 70.5 240.5 519.0
22 BX AsIs 72.6 313.1 519.0
23 BY AsIs 30.7 343.8 519.0
24 BZ AsIs 35.6 379.4 519.0
25 CX AsIs 5.2 384.6 519.0
26 CY AsIs 44.8 429.4 519.0
27 CZ AsIs 89.6 519.0 519.0
By creating a hjust variable, you can achieve the desired result. The code:
mydf$hj <- rep(c(1,0,-1), length.out=27)
ggplot(mydf, aes(x=variable, y=value, fill=Category)) +
geom_bar(stat="identity") +
geom_text(aes(label=value, y=pos-(value/2), hjust=hj), size=4)
which gives:
A slightly alternative solution proposed by #konvas:
ggplot(mydf, aes(x=variable, y=value, fill=Category)) +
geom_bar(stat="identity") +
geom_text(aes(label=value, y=pos-(value/2), hjust=rep(c(1,0,-1), length.out=length(value))), size=4)